| author | |
| committer | |
| log | 259f3458a162120288eb80dea4e55cd4ed9cf4c5 |
| tree | be93f1e502b55b3d831d2cb1f267810d083df3c0 |
| parent | 5789036b86bcc95b2e017ed7330aaf7ccbfa3d5f |
4 files changed, 726 insertions(+), 718 deletions(-)
src/Sema.zig+7-3| ... | ... | @@ -139,7 +139,7 @@ pub fn analyzeBody( |
| 139 | 139 | .alloc => try sema.zirAlloc(block, inst), |
| 140 | 140 | .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), |
| 141 | 141 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), |
| 142 | .alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst), | |
| 142 | .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst), | |
| 143 | 143 | .alloc_mut => try sema.zirAllocMut(block, inst), |
| 144 | 144 | .alloc_comptime => try sema.zirAllocComptime(block, inst), |
| 145 | 145 | .anyframe_type => try sema.zirAnyframeType(block, inst), |
| ... | ... | @@ -1384,10 +1384,14 @@ fn zirAllocComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp |
| 1384 | 1384 | return sema.analyzeComptimeAlloc(block, var_type); |
| 1385 | 1385 | } |
| 1386 | 1386 | |
| 1387 | fn zirAllocInferredComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 1387 | fn zirAllocInferredComptime(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 1388 | 1388 | const src_node = sema.code.instructions.items(.data)[inst].node; |
| 1389 | 1389 | const src: LazySrcLoc = .{ .node_offset = src_node }; |
| 1390 | return sema.mod.fail(&block.base, src, "TODO implement Sema.zirAllocInferredComptime", .{}); | |
| 1390 | sema.src = src; | |
| 1391 | return sema.addConstant( | |
| 1392 | Type.initTag(.inferred_alloc_mut), | |
| 1393 | try Value.Tag.inferred_alloc_comptime.create(sema.arena, undefined), | |
| 1394 | ); | |
| 1391 | 1395 | } |
| 1392 | 1396 | |
| 1393 | 1397 | fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
test/behavior.zig+2-1| ... | ... | @@ -5,6 +5,7 @@ test { |
| 5 | 5 | _ = @import("behavior/bool.zig"); |
| 6 | 6 | _ = @import("behavior/basic.zig"); |
| 7 | 7 | _ = @import("behavior/generics.zig"); |
| 8 | _ = @import("behavior/eval.zig"); | |
| 8 | 9 | |
| 9 | 10 | if (!builtin.zig_is_stage2) { |
| 10 | 11 | // Tests that only pass for stage1. |
| ... | ... | @@ -88,7 +89,7 @@ test { |
| 88 | 89 | _ = @import("behavior/enum.zig"); |
| 89 | 90 | _ = @import("behavior/enum_with_members.zig"); |
| 90 | 91 | _ = @import("behavior/error.zig"); |
| 91 | _ = @import("behavior/eval.zig"); | |
| 92 | _ = @import("behavior/eval_stage1.zig"); | |
| 92 | 93 | _ = @import("behavior/field_parent_ptr.zig"); |
| 93 | 94 | _ = @import("behavior/floatop.zig"); |
| 94 | 95 | _ = @import("behavior/fn.zig"); |
test/behavior/eval.zig-714| ... | ... | @@ -63,146 +63,12 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { |
| 63 | 63 | return result; |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | test "statically initialized list" { | |
| 67 | try expect(static_point_list[0].x == 1); | |
| 68 | try expect(static_point_list[0].y == 2); | |
| 69 | try expect(static_point_list[1].x == 3); | |
| 70 | try expect(static_point_list[1].y == 4); | |
| 71 | } | |
| 72 | const Point = struct { | |
| 73 | x: i32, | |
| 74 | y: i32, | |
| 75 | }; | |
| 76 | const static_point_list = [_]Point{ | |
| 77 | makePoint(1, 2), | |
| 78 | makePoint(3, 4), | |
| 79 | }; | |
| 80 | fn makePoint(x: i32, y: i32) Point { | |
| 81 | return Point{ | |
| 82 | .x = x, | |
| 83 | .y = y, | |
| 84 | }; | |
| 85 | } | |
| 86 | ||
| 87 | test "static eval list init" { | |
| 88 | try expect(static_vec3.data[2] == 1.0); | |
| 89 | try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); | |
| 90 | } | |
| 91 | const static_vec3 = vec3(0.0, 0.0, 1.0); | |
| 92 | pub const Vec3 = struct { | |
| 93 | data: [3]f32, | |
| 94 | }; | |
| 95 | pub fn vec3(x: f32, y: f32, z: f32) Vec3 { | |
| 96 | return Vec3{ | |
| 97 | .data = [_]f32{ | |
| 98 | x, | |
| 99 | y, | |
| 100 | z, | |
| 101 | }, | |
| 102 | }; | |
| 103 | } | |
| 104 | ||
| 105 | 66 | test "constant expressions" { |
| 106 | 67 | var array: [array_size]u8 = undefined; |
| 107 | 68 | try expect(@sizeOf(@TypeOf(array)) == 20); |
| 108 | 69 | } |
| 109 | 70 | const array_size: u8 = 20; |
| 110 | 71 | |
| 111 | test "constant struct with negation" { | |
| 112 | try expect(vertices[0].x == -0.6); | |
| 113 | } | |
| 114 | const Vertex = struct { | |
| 115 | x: f32, | |
| 116 | y: f32, | |
| 117 | r: f32, | |
| 118 | g: f32, | |
| 119 | b: f32, | |
| 120 | }; | |
| 121 | const vertices = [_]Vertex{ | |
| 122 | Vertex{ | |
| 123 | .x = -0.6, | |
| 124 | .y = -0.4, | |
| 125 | .r = 1.0, | |
| 126 | .g = 0.0, | |
| 127 | .b = 0.0, | |
| 128 | }, | |
| 129 | Vertex{ | |
| 130 | .x = 0.6, | |
| 131 | .y = -0.4, | |
| 132 | .r = 0.0, | |
| 133 | .g = 1.0, | |
| 134 | .b = 0.0, | |
| 135 | }, | |
| 136 | Vertex{ | |
| 137 | .x = 0.0, | |
| 138 | .y = 0.6, | |
| 139 | .r = 0.0, | |
| 140 | .g = 0.0, | |
| 141 | .b = 1.0, | |
| 142 | }, | |
| 143 | }; | |
| 144 | ||
| 145 | test "statically initialized struct" { | |
| 146 | st_init_str_foo.x += 1; | |
| 147 | try expect(st_init_str_foo.x == 14); | |
| 148 | } | |
| 149 | const StInitStrFoo = struct { | |
| 150 | x: i32, | |
| 151 | y: bool, | |
| 152 | }; | |
| 153 | var st_init_str_foo = StInitStrFoo{ | |
| 154 | .x = 13, | |
| 155 | .y = true, | |
| 156 | }; | |
| 157 | ||
| 158 | test "statically initalized array literal" { | |
| 159 | const y: [4]u8 = st_init_arr_lit_x; | |
| 160 | try expect(y[3] == 4); | |
| 161 | } | |
| 162 | const st_init_arr_lit_x = [_]u8{ | |
| 163 | 1, | |
| 164 | 2, | |
| 165 | 3, | |
| 166 | 4, | |
| 167 | }; | |
| 168 | ||
| 169 | test "const slice" { | |
| 170 | comptime { | |
| 171 | const a = "1234567890"; | |
| 172 | try expect(a.len == 10); | |
| 173 | const b = a[1..2]; | |
| 174 | try expect(b.len == 1); | |
| 175 | try expect(b[0] == '2'); | |
| 176 | } | |
| 177 | } | |
| 178 | ||
| 179 | test "try to trick eval with runtime if" { | |
| 180 | try expect(testTryToTrickEvalWithRuntimeIf(true) == 10); | |
| 181 | } | |
| 182 | ||
| 183 | fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { | |
| 184 | comptime var i: usize = 0; | |
| 185 | inline while (i < 10) : (i += 1) { | |
| 186 | const result = if (b) false else true; | |
| 187 | _ = result; | |
| 188 | } | |
| 189 | comptime { | |
| 190 | return i; | |
| 191 | } | |
| 192 | } | |
| 193 | ||
| 194 | test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" { | |
| 195 | var runtime = [1]i32{3}; | |
| 196 | comptime var i: usize = 0; | |
| 197 | inline while (i < 2) : (i += 1) { | |
| 198 | const result = if (i == 0) [1]i32{2} else runtime; | |
| 199 | _ = result; | |
| 200 | } | |
| 201 | comptime { | |
| 202 | try expect(i == 2); | |
| 203 | } | |
| 204 | } | |
| 205 | ||
| 206 | 72 | fn max(comptime T: type, a: T, b: T) T { |
| 207 | 73 | if (T == bool) { |
| 208 | 74 | return a or b; |
| ... | ... | @@ -229,52 +95,6 @@ test "inlined block and runtime block phi" { |
| 229 | 95 | } |
| 230 | 96 | } |
| 231 | 97 | |
| 232 | const CmdFn = struct { | |
| 233 | name: []const u8, | |
| 234 | func: fn (i32) i32, | |
| 235 | }; | |
| 236 | ||
| 237 | const cmd_fns = [_]CmdFn{ | |
| 238 | CmdFn{ | |
| 239 | .name = "one", | |
| 240 | .func = one, | |
| 241 | }, | |
| 242 | CmdFn{ | |
| 243 | .name = "two", | |
| 244 | .func = two, | |
| 245 | }, | |
| 246 | CmdFn{ | |
| 247 | .name = "three", | |
| 248 | .func = three, | |
| 249 | }, | |
| 250 | }; | |
| 251 | fn one(value: i32) i32 { | |
| 252 | return value + 1; | |
| 253 | } | |
| 254 | fn two(value: i32) i32 { | |
| 255 | return value + 2; | |
| 256 | } | |
| 257 | fn three(value: i32) i32 { | |
| 258 | return value + 3; | |
| 259 | } | |
| 260 | ||
| 261 | fn performFn(comptime prefix_char: u8, start_value: i32) i32 { | |
| 262 | var result: i32 = start_value; | |
| 263 | comptime var i = 0; | |
| 264 | inline while (i < cmd_fns.len) : (i += 1) { | |
| 265 | if (cmd_fns[i].name[0] == prefix_char) { | |
| 266 | result = cmd_fns[i].func(result); | |
| 267 | } | |
| 268 | } | |
| 269 | return result; | |
| 270 | } | |
| 271 | ||
| 272 | test "comptime iterate over fn ptr list" { | |
| 273 | try expect(performFn('t', 1) == 6); | |
| 274 | try expect(performFn('o', 0) == 1); | |
| 275 | try expect(performFn('w', 99) == 99); | |
| 276 | } | |
| 277 | ||
| 278 | 98 | test "eval @setRuntimeSafety at compile-time" { |
| 279 | 99 | const result = comptime fnWithSetRuntimeSafety(); |
| 280 | 100 | try expect(result == 1234); |
| ... | ... | @@ -285,90 +105,6 @@ fn fnWithSetRuntimeSafety() i32 { |
| 285 | 105 | return 1234; |
| 286 | 106 | } |
| 287 | 107 | |
| 288 | test "eval @setFloatMode at compile-time" { | |
| 289 | const result = comptime fnWithFloatMode(); | |
| 290 | try expect(result == 1234.0); | |
| 291 | } | |
| 292 | ||
| 293 | fn fnWithFloatMode() f32 { | |
| 294 | @setFloatMode(std.builtin.FloatMode.Strict); | |
| 295 | return 1234.0; | |
| 296 | } | |
| 297 | ||
| 298 | const SimpleStruct = struct { | |
| 299 | field: i32, | |
| 300 | ||
| 301 | fn method(self: *const SimpleStruct) i32 { | |
| 302 | return self.field + 3; | |
| 303 | } | |
| 304 | }; | |
| 305 | ||
| 306 | var simple_struct = SimpleStruct{ .field = 1234 }; | |
| 307 | ||
| 308 | const bound_fn = simple_struct.method; | |
| 309 | ||
| 310 | test "call method on bound fn referring to var instance" { | |
| 311 | try expect(bound_fn() == 1237); | |
| 312 | } | |
| 313 | ||
| 314 | test "ptr to local array argument at comptime" { | |
| 315 | comptime { | |
| 316 | var bytes: [10]u8 = undefined; | |
| 317 | modifySomeBytes(bytes[0..]); | |
| 318 | try expect(bytes[0] == 'a'); | |
| 319 | try expect(bytes[9] == 'b'); | |
| 320 | } | |
| 321 | } | |
| 322 | ||
| 323 | fn modifySomeBytes(bytes: []u8) void { | |
| 324 | bytes[0] = 'a'; | |
| 325 | bytes[9] = 'b'; | |
| 326 | } | |
| 327 | ||
| 328 | test "comparisons 0 <= uint and 0 > uint should be comptime" { | |
| 329 | testCompTimeUIntComparisons(1234); | |
| 330 | } | |
| 331 | fn testCompTimeUIntComparisons(x: u32) void { | |
| 332 | if (!(0 <= x)) { | |
| 333 | @compileError("this condition should be comptime known"); | |
| 334 | } | |
| 335 | if (0 > x) { | |
| 336 | @compileError("this condition should be comptime known"); | |
| 337 | } | |
| 338 | if (!(x >= 0)) { | |
| 339 | @compileError("this condition should be comptime known"); | |
| 340 | } | |
| 341 | if (x < 0) { | |
| 342 | @compileError("this condition should be comptime known"); | |
| 343 | } | |
| 344 | } | |
| 345 | ||
| 346 | test "const ptr to variable data changes at runtime" { | |
| 347 | try expect(foo_ref.name[0] == 'a'); | |
| 348 | foo_ref.name = "b"; | |
| 349 | try expect(foo_ref.name[0] == 'b'); | |
| 350 | } | |
| 351 | ||
| 352 | const Foo = struct { | |
| 353 | name: []const u8, | |
| 354 | }; | |
| 355 | ||
| 356 | var foo_contents = Foo{ .name = "a" }; | |
| 357 | const foo_ref = &foo_contents; | |
| 358 | ||
| 359 | test "create global array with for loop" { | |
| 360 | try expect(global_array[5] == 5 * 5); | |
| 361 | try expect(global_array[9] == 9 * 9); | |
| 362 | } | |
| 363 | ||
| 364 | const global_array = x: { | |
| 365 | var result: [10]usize = undefined; | |
| 366 | for (result) |*item, index| { | |
| 367 | item.* = index * index; | |
| 368 | } | |
| 369 | break :x result; | |
| 370 | }; | |
| 371 | ||
| 372 | 108 | test "compile-time downcast when the bits fit" { |
| 373 | 109 | comptime { |
| 374 | 110 | const spartan_count: u16 = 255; |
| ... | ... | @@ -377,231 +113,6 @@ test "compile-time downcast when the bits fit" { |
| 377 | 113 | } |
| 378 | 114 | } |
| 379 | 115 | |
| 380 | const hi1 = "hi"; | |
| 381 | const hi2 = hi1; | |
| 382 | test "const global shares pointer with other same one" { | |
| 383 | try assertEqualPtrs(&hi1[0], &hi2[0]); | |
| 384 | comptime try expect(&hi1[0] == &hi2[0]); | |
| 385 | } | |
| 386 | fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) !void { | |
| 387 | try expect(ptr1 == ptr2); | |
| 388 | } | |
| 389 | ||
| 390 | test "@setEvalBranchQuota" { | |
| 391 | comptime { | |
| 392 | // 1001 for the loop and then 1 more for the expect fn call | |
| 393 | @setEvalBranchQuota(1002); | |
| 394 | var i = 0; | |
| 395 | var sum = 0; | |
| 396 | while (i < 1001) : (i += 1) { | |
| 397 | sum += i; | |
| 398 | } | |
| 399 | try expect(sum == 500500); | |
| 400 | } | |
| 401 | } | |
| 402 | ||
| 403 | test "float literal at compile time not lossy" { | |
| 404 | try expect(16777216.0 + 1.0 == 16777217.0); | |
| 405 | try expect(9007199254740992.0 + 1.0 == 9007199254740993.0); | |
| 406 | } | |
| 407 | ||
| 408 | test "f32 at compile time is lossy" { | |
| 409 | try expect(@as(f32, 1 << 24) + 1 == 1 << 24); | |
| 410 | } | |
| 411 | ||
| 412 | test "f64 at compile time is lossy" { | |
| 413 | try expect(@as(f64, 1 << 53) + 1 == 1 << 53); | |
| 414 | } | |
| 415 | ||
| 416 | test "f128 at compile time is lossy" { | |
| 417 | try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); | |
| 418 | } | |
| 419 | ||
| 420 | test { | |
| 421 | comptime try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192); | |
| 422 | } | |
| 423 | ||
| 424 | pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { | |
| 425 | _ = field_name; | |
| 426 | return struct { | |
| 427 | pub const Node = struct {}; | |
| 428 | }; | |
| 429 | } | |
| 430 | ||
| 431 | test "string literal used as comptime slice is memoized" { | |
| 432 | const a = "link"; | |
| 433 | const b = "link"; | |
| 434 | comptime try expect(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); | |
| 435 | comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); | |
| 436 | } | |
| 437 | ||
| 438 | test "comptime slice of undefined pointer of length 0" { | |
| 439 | const slice1 = @as([*]i32, undefined)[0..0]; | |
| 440 | try expect(slice1.len == 0); | |
| 441 | const slice2 = @as([*]i32, undefined)[100..100]; | |
| 442 | try expect(slice2.len == 0); | |
| 443 | } | |
| 444 | ||
| 445 | fn copyWithPartialInline(s: []u32, b: []u8) void { | |
| 446 | comptime var i: usize = 0; | |
| 447 | inline while (i < 4) : (i += 1) { | |
| 448 | s[i] = 0; | |
| 449 | s[i] |= @as(u32, b[i * 4 + 0]) << 24; | |
| 450 | s[i] |= @as(u32, b[i * 4 + 1]) << 16; | |
| 451 | s[i] |= @as(u32, b[i * 4 + 2]) << 8; | |
| 452 | s[i] |= @as(u32, b[i * 4 + 3]) << 0; | |
| 453 | } | |
| 454 | } | |
| 455 | ||
| 456 | test "binary math operator in partially inlined function" { | |
| 457 | var s: [4]u32 = undefined; | |
| 458 | var b: [16]u8 = undefined; | |
| 459 | ||
| 460 | for (b) |*r, i| | |
| 461 | r.* = @intCast(u8, i + 1); | |
| 462 | ||
| 463 | copyWithPartialInline(s[0..], b[0..]); | |
| 464 | try expect(s[0] == 0x1020304); | |
| 465 | try expect(s[1] == 0x5060708); | |
| 466 | try expect(s[2] == 0x90a0b0c); | |
| 467 | try expect(s[3] == 0xd0e0f10); | |
| 468 | } | |
| 469 | ||
| 470 | test "comptime function with the same args is memoized" { | |
| 471 | comptime { | |
| 472 | try expect(MakeType(i32) == MakeType(i32)); | |
| 473 | try expect(MakeType(i32) != MakeType(f64)); | |
| 474 | } | |
| 475 | } | |
| 476 | ||
| 477 | fn MakeType(comptime T: type) type { | |
| 478 | return struct { | |
| 479 | field: T, | |
| 480 | }; | |
| 481 | } | |
| 482 | ||
| 483 | test "comptime function with mutable pointer is not memoized" { | |
| 484 | comptime { | |
| 485 | var x: i32 = 1; | |
| 486 | const ptr = &x; | |
| 487 | increment(ptr); | |
| 488 | increment(ptr); | |
| 489 | try expect(x == 3); | |
| 490 | } | |
| 491 | } | |
| 492 | ||
| 493 | fn increment(value: *i32) void { | |
| 494 | value.* += 1; | |
| 495 | } | |
| 496 | ||
| 497 | fn generateTable(comptime T: type) [1010]T { | |
| 498 | var res: [1010]T = undefined; | |
| 499 | var i: usize = 0; | |
| 500 | while (i < 1010) : (i += 1) { | |
| 501 | res[i] = @intCast(T, i); | |
| 502 | } | |
| 503 | return res; | |
| 504 | } | |
| 505 | ||
| 506 | fn doesAlotT(comptime T: type, value: usize) T { | |
| 507 | @setEvalBranchQuota(5000); | |
| 508 | const table = comptime blk: { | |
| 509 | break :blk generateTable(T); | |
| 510 | }; | |
| 511 | return table[value]; | |
| 512 | } | |
| 513 | ||
| 514 | test "@setEvalBranchQuota at same scope as generic function call" { | |
| 515 | try expect(doesAlotT(u32, 2) == 2); | |
| 516 | } | |
| 517 | ||
| 518 | test "comptime slice of slice preserves comptime var" { | |
| 519 | comptime { | |
| 520 | var buff: [10]u8 = undefined; | |
| 521 | buff[0..][0..][0] = 1; | |
| 522 | try expect(buff[0..][0..][0] == 1); | |
| 523 | } | |
| 524 | } | |
| 525 | ||
| 526 | test "comptime slice of pointer preserves comptime var" { | |
| 527 | comptime { | |
| 528 | var buff: [10]u8 = undefined; | |
| 529 | var a = @ptrCast([*]u8, &buff); | |
| 530 | a[0..1][0] = 1; | |
| 531 | try expect(buff[0..][0..][0] == 1); | |
| 532 | } | |
| 533 | } | |
| 534 | ||
| 535 | const SingleFieldStruct = struct { | |
| 536 | x: i32, | |
| 537 | ||
| 538 | fn read_x(self: *const SingleFieldStruct) i32 { | |
| 539 | return self.x; | |
| 540 | } | |
| 541 | }; | |
| 542 | test "const ptr to comptime mutable data is not memoized" { | |
| 543 | comptime { | |
| 544 | var foo = SingleFieldStruct{ .x = 1 }; | |
| 545 | try expect(foo.read_x() == 1); | |
| 546 | foo.x = 2; | |
| 547 | try expect(foo.read_x() == 2); | |
| 548 | } | |
| 549 | } | |
| 550 | ||
| 551 | test "array concat of slices gives slice" { | |
| 552 | comptime { | |
| 553 | var a: []const u8 = "aoeu"; | |
| 554 | var b: []const u8 = "asdf"; | |
| 555 | const c = a ++ b; | |
| 556 | try expect(std.mem.eql(u8, c, "aoeuasdf")); | |
| 557 | } | |
| 558 | } | |
| 559 | ||
| 560 | test "comptime shlWithOverflow" { | |
| 561 | const ct_shifted: u64 = comptime amt: { | |
| 562 | var amt = @as(u64, 0); | |
| 563 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | |
| 564 | break :amt amt; | |
| 565 | }; | |
| 566 | ||
| 567 | const rt_shifted: u64 = amt: { | |
| 568 | var amt = @as(u64, 0); | |
| 569 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | |
| 570 | break :amt amt; | |
| 571 | }; | |
| 572 | ||
| 573 | try expect(ct_shifted == rt_shifted); | |
| 574 | } | |
| 575 | ||
| 576 | test "comptime shl" { | |
| 577 | var a: u128 = 3; | |
| 578 | var b: u7 = 63; | |
| 579 | var c: u128 = 3 << 63; | |
| 580 | try expectEqual(a << b, c); | |
| 581 | } | |
| 582 | ||
| 583 | test "runtime 128 bit integer division" { | |
| 584 | var a: u128 = 152313999999999991610955792383; | |
| 585 | var b: u128 = 10000000000000000000; | |
| 586 | var c = a / b; | |
| 587 | try expect(c == 15231399999); | |
| 588 | } | |
| 589 | ||
| 590 | pub const Info = struct { | |
| 591 | version: u8, | |
| 592 | }; | |
| 593 | ||
| 594 | pub const diamond_info = Info{ .version = 0 }; | |
| 595 | ||
| 596 | test "comptime modification of const struct field" { | |
| 597 | comptime { | |
| 598 | var res = diamond_info; | |
| 599 | res.version = 1; | |
| 600 | try expect(diamond_info.version == 0); | |
| 601 | try expect(res.version == 1); | |
| 602 | } | |
| 603 | } | |
| 604 | ||
| 605 | 116 | test "pointer to type" { |
| 606 | 117 | comptime { |
| 607 | 118 | var T: type = i32; |
| ... | ... | @@ -614,233 +125,8 @@ test "pointer to type" { |
| 614 | 125 | } |
| 615 | 126 | } |
| 616 | 127 | |
| 617 | test "slice of type" { | |
| 618 | comptime { | |
| 619 | var types_array = [_]type{ i32, f64, type }; | |
| 620 | for (types_array) |T, i| { | |
| 621 | switch (i) { | |
| 622 | 0 => try expect(T == i32), | |
| 623 | 1 => try expect(T == f64), | |
| 624 | 2 => try expect(T == type), | |
| 625 | else => unreachable, | |
| 626 | } | |
| 627 | } | |
| 628 | for (types_array[0..]) |T, i| { | |
| 629 | switch (i) { | |
| 630 | 0 => try expect(T == i32), | |
| 631 | 1 => try expect(T == f64), | |
| 632 | 2 => try expect(T == type), | |
| 633 | else => unreachable, | |
| 634 | } | |
| 635 | } | |
| 636 | } | |
| 637 | } | |
| 638 | ||
| 639 | const Wrapper = struct { | |
| 640 | T: type, | |
| 641 | }; | |
| 642 | ||
| 643 | fn wrap(comptime T: type) Wrapper { | |
| 644 | return Wrapper{ .T = T }; | |
| 645 | } | |
| 646 | ||
| 647 | test "function which returns struct with type field causes implicit comptime" { | |
| 648 | const ty = wrap(i32).T; | |
| 649 | try expect(ty == i32); | |
| 650 | } | |
| 651 | ||
| 652 | test "call method with comptime pass-by-non-copying-value self parameter" { | |
| 653 | const S = struct { | |
| 654 | a: u8, | |
| 655 | ||
| 656 | fn b(comptime s: @This()) u8 { | |
| 657 | return s.a; | |
| 658 | } | |
| 659 | }; | |
| 660 | ||
| 661 | const s = S{ .a = 2 }; | |
| 662 | var b = s.b(); | |
| 663 | try expect(b == 2); | |
| 664 | } | |
| 665 | ||
| 666 | test "@tagName of @typeInfo" { | |
| 667 | const str = @tagName(@typeInfo(u8)); | |
| 668 | try expect(std.mem.eql(u8, str, "Int")); | |
| 669 | } | |
| 670 | ||
| 671 | test "setting backward branch quota just before a generic fn call" { | |
| 672 | @setEvalBranchQuota(1001); | |
| 673 | loopNTimes(1001); | |
| 674 | } | |
| 675 | ||
| 676 | fn loopNTimes(comptime n: usize) void { | |
| 677 | comptime var i = 0; | |
| 678 | inline while (i < n) : (i += 1) {} | |
| 679 | } | |
| 680 | ||
| 681 | test "variable inside inline loop that has different types on different iterations" { | |
| 682 | try testVarInsideInlineLoop(.{ true, @as(u32, 42) }); | |
| 683 | } | |
| 684 | ||
| 685 | fn testVarInsideInlineLoop(args: anytype) !void { | |
| 686 | comptime var i = 0; | |
| 687 | inline while (i < args.len) : (i += 1) { | |
| 688 | const x = args[i]; | |
| 689 | if (i == 0) try expect(x); | |
| 690 | if (i == 1) try expect(x == 42); | |
| 691 | } | |
| 692 | } | |
| 693 | ||
| 694 | test "inline for with same type but different values" { | |
| 695 | var res: usize = 0; | |
| 696 | inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| { | |
| 697 | var a: T = undefined; | |
| 698 | res += a.len; | |
| 699 | } | |
| 700 | try expect(res == 5); | |
| 701 | } | |
| 702 | ||
| 703 | test "refer to the type of a generic function" { | |
| 704 | const Func = fn (type) void; | |
| 705 | const f: Func = doNothingWithType; | |
| 706 | f(i32); | |
| 707 | } | |
| 708 | ||
| 709 | fn doNothingWithType(comptime T: type) void { | |
| 710 | _ = T; | |
| 711 | } | |
| 712 | ||
| 713 | test "zero extend from u0 to u1" { | |
| 714 | var zero_u0: u0 = 0; | |
| 715 | var zero_u1: u1 = zero_u0; | |
| 716 | try expect(zero_u1 == 0); | |
| 717 | } | |
| 718 | ||
| 719 | test "bit shift a u1" { | |
| 720 | var x: u1 = 1; | |
| 721 | var y = x << 0; | |
| 722 | try expect(y == 1); | |
| 723 | } | |
| 724 | ||
| 725 | test "comptime pointer cast array and then slice" { | |
| 726 | const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; | |
| 727 | ||
| 728 | const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); | |
| 729 | const sliceA: []const u8 = ptrA[0..2]; | |
| 730 | ||
| 731 | const ptrB: [*]const u8 = &array; | |
| 732 | const sliceB: []const u8 = ptrB[0..2]; | |
| 733 | ||
| 734 | try expect(sliceA[1] == 2); | |
| 735 | try expect(sliceB[1] == 2); | |
| 736 | } | |
| 737 | ||
| 738 | test "slice bounds in comptime concatenation" { | |
| 739 | const bs = comptime blk: { | |
| 740 | const b = "........1........"; | |
| 741 | break :blk b[8..9]; | |
| 742 | }; | |
| 743 | const str = "" ++ bs; | |
| 744 | try expect(str.len == 1); | |
| 745 | try expect(std.mem.eql(u8, str, "1")); | |
| 746 | ||
| 747 | const str2 = bs ++ ""; | |
| 748 | try expect(str2.len == 1); | |
| 749 | try expect(std.mem.eql(u8, str2, "1")); | |
| 750 | } | |
| 751 | ||
| 752 | test "comptime bitwise operators" { | |
| 753 | comptime { | |
| 754 | try expect(3 & 1 == 1); | |
| 755 | try expect(3 & -1 == 3); | |
| 756 | try expect(-3 & -1 == -3); | |
| 757 | try expect(3 | -1 == -1); | |
| 758 | try expect(-3 | -1 == -1); | |
| 759 | try expect(3 ^ -1 == -4); | |
| 760 | try expect(-3 ^ -1 == 2); | |
| 761 | try expect(~@as(i8, -1) == 0); | |
| 762 | try expect(~@as(i128, -1) == 0); | |
| 763 | try expect(18446744073709551615 & 18446744073709551611 == 18446744073709551611); | |
| 764 | try expect(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); | |
| 765 | try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff); | |
| 766 | } | |
| 767 | } | |
| 768 | ||
| 769 | test "*align(1) u16 is the same as *align(1:0:2) u16" { | |
| 770 | comptime { | |
| 771 | try expect(*align(1:0:2) u16 == *align(1) u16); | |
| 772 | try expect(*align(2:0:2) u16 == *u16); | |
| 773 | } | |
| 774 | } | |
| 775 | ||
| 776 | test "array concatenation forces comptime" { | |
| 777 | var a = oneItem(3) ++ oneItem(4); | |
| 778 | try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 })); | |
| 779 | } | |
| 780 | ||
| 781 | test "array multiplication forces comptime" { | |
| 782 | var a = oneItem(3) ** scalar(2); | |
| 783 | try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 })); | |
| 784 | } | |
| 785 | ||
| 786 | fn oneItem(x: i32) [1]i32 { | |
| 787 | return [_]i32{x}; | |
| 788 | } | |
| 789 | ||
| 790 | fn scalar(x: u32) u32 { | |
| 791 | return x; | |
| 792 | } | |
| 793 | ||
| 794 | 128 | test "no undeclared identifier error in unanalyzed branches" { |
| 795 | 129 | if (false) { |
| 796 | 130 | lol_this_doesnt_exist = nonsense; |
| 797 | 131 | } |
| 798 | 132 | } |
| 799 | ||
| 800 | test "comptime assign int to optional int" { | |
| 801 | comptime { | |
| 802 | var x: ?i32 = null; | |
| 803 | x = 2; | |
| 804 | x.? *= 10; | |
| 805 | try expectEqual(20, x.?); | |
| 806 | } | |
| 807 | } | |
| 808 | ||
| 809 | test "return 0 from function that has u0 return type" { | |
| 810 | const S = struct { | |
| 811 | fn foo_zero() u0 { | |
| 812 | return 0; | |
| 813 | } | |
| 814 | }; | |
| 815 | comptime { | |
| 816 | if (S.foo_zero() != 0) { | |
| 817 | @compileError("test failed"); | |
| 818 | } | |
| 819 | } | |
| 820 | } | |
| 821 | ||
| 822 | test "two comptime calls with array default initialized to undefined" { | |
| 823 | const S = struct { | |
| 824 | const CrossTarget = struct { | |
| 825 | dynamic_linker: DynamicLinker = DynamicLinker{}, | |
| 826 | ||
| 827 | pub fn parse() void { | |
| 828 | var result: CrossTarget = .{}; | |
| 829 | result.getCpuArch(); | |
| 830 | } | |
| 831 | ||
| 832 | pub fn getCpuArch(self: CrossTarget) void { | |
| 833 | _ = self; | |
| 834 | } | |
| 835 | }; | |
| 836 | ||
| 837 | const DynamicLinker = struct { | |
| 838 | buffer: [255]u8 = undefined, | |
| 839 | }; | |
| 840 | }; | |
| 841 | ||
| 842 | comptime { | |
| 843 | S.CrossTarget.parse(); | |
| 844 | S.CrossTarget.parse(); | |
| 845 | } | |
| 846 | } |
test/behavior/eval_stage1.zig created+717| ... | ... | @@ -0,0 +1,717 @@ |
| 1 | const std = @import("std"); | |
| 2 | const expect = std.testing.expect; | |
| 3 | const expectEqual = std.testing.expectEqual; | |
| 4 | ||
| 5 | test "statically initialized list" { | |
| 6 | try expect(static_point_list[0].x == 1); | |
| 7 | try expect(static_point_list[0].y == 2); | |
| 8 | try expect(static_point_list[1].x == 3); | |
| 9 | try expect(static_point_list[1].y == 4); | |
| 10 | } | |
| 11 | const Point = struct { | |
| 12 | x: i32, | |
| 13 | y: i32, | |
| 14 | }; | |
| 15 | const static_point_list = [_]Point{ | |
| 16 | makePoint(1, 2), | |
| 17 | makePoint(3, 4), | |
| 18 | }; | |
| 19 | fn makePoint(x: i32, y: i32) Point { | |
| 20 | return Point{ | |
| 21 | .x = x, | |
| 22 | .y = y, | |
| 23 | }; | |
| 24 | } | |
| 25 | ||
| 26 | test "static eval list init" { | |
| 27 | try expect(static_vec3.data[2] == 1.0); | |
| 28 | try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); | |
| 29 | } | |
| 30 | const static_vec3 = vec3(0.0, 0.0, 1.0); | |
| 31 | pub const Vec3 = struct { | |
| 32 | data: [3]f32, | |
| 33 | }; | |
| 34 | pub fn vec3(x: f32, y: f32, z: f32) Vec3 { | |
| 35 | return Vec3{ | |
| 36 | .data = [_]f32{ | |
| 37 | x, | |
| 38 | y, | |
| 39 | z, | |
| 40 | }, | |
| 41 | }; | |
| 42 | } | |
| 43 | ||
| 44 | test "constant struct with negation" { | |
| 45 | try expect(vertices[0].x == -0.6); | |
| 46 | } | |
| 47 | const Vertex = struct { | |
| 48 | x: f32, | |
| 49 | y: f32, | |
| 50 | r: f32, | |
| 51 | g: f32, | |
| 52 | b: f32, | |
| 53 | }; | |
| 54 | const vertices = [_]Vertex{ | |
| 55 | Vertex{ | |
| 56 | .x = -0.6, | |
| 57 | .y = -0.4, | |
| 58 | .r = 1.0, | |
| 59 | .g = 0.0, | |
| 60 | .b = 0.0, | |
| 61 | }, | |
| 62 | Vertex{ | |
| 63 | .x = 0.6, | |
| 64 | .y = -0.4, | |
| 65 | .r = 0.0, | |
| 66 | .g = 1.0, | |
| 67 | .b = 0.0, | |
| 68 | }, | |
| 69 | Vertex{ | |
| 70 | .x = 0.0, | |
| 71 | .y = 0.6, | |
| 72 | .r = 0.0, | |
| 73 | .g = 0.0, | |
| 74 | .b = 1.0, | |
| 75 | }, | |
| 76 | }; | |
| 77 | ||
| 78 | test "statically initialized struct" { | |
| 79 | st_init_str_foo.x += 1; | |
| 80 | try expect(st_init_str_foo.x == 14); | |
| 81 | } | |
| 82 | const StInitStrFoo = struct { | |
| 83 | x: i32, | |
| 84 | y: bool, | |
| 85 | }; | |
| 86 | var st_init_str_foo = StInitStrFoo{ | |
| 87 | .x = 13, | |
| 88 | .y = true, | |
| 89 | }; | |
| 90 | ||
| 91 | test "statically initalized array literal" { | |
| 92 | const y: [4]u8 = st_init_arr_lit_x; | |
| 93 | try expect(y[3] == 4); | |
| 94 | } | |
| 95 | const st_init_arr_lit_x = [_]u8{ | |
| 96 | 1, | |
| 97 | 2, | |
| 98 | 3, | |
| 99 | 4, | |
| 100 | }; | |
| 101 | ||
| 102 | test "const slice" { | |
| 103 | comptime { | |
| 104 | const a = "1234567890"; | |
| 105 | try expect(a.len == 10); | |
| 106 | const b = a[1..2]; | |
| 107 | try expect(b.len == 1); | |
| 108 | try expect(b[0] == '2'); | |
| 109 | } | |
| 110 | } | |
| 111 | ||
| 112 | test "try to trick eval with runtime if" { | |
| 113 | try expect(testTryToTrickEvalWithRuntimeIf(true) == 10); | |
| 114 | } | |
| 115 | ||
| 116 | fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { | |
| 117 | comptime var i: usize = 0; | |
| 118 | inline while (i < 10) : (i += 1) { | |
| 119 | const result = if (b) false else true; | |
| 120 | _ = result; | |
| 121 | } | |
| 122 | comptime { | |
| 123 | return i; | |
| 124 | } | |
| 125 | } | |
| 126 | ||
| 127 | test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" { | |
| 128 | var runtime = [1]i32{3}; | |
| 129 | comptime var i: usize = 0; | |
| 130 | inline while (i < 2) : (i += 1) { | |
| 131 | const result = if (i == 0) [1]i32{2} else runtime; | |
| 132 | _ = result; | |
| 133 | } | |
| 134 | comptime { | |
| 135 | try expect(i == 2); | |
| 136 | } | |
| 137 | } | |
| 138 | ||
| 139 | const CmdFn = struct { | |
| 140 | name: []const u8, | |
| 141 | func: fn (i32) i32, | |
| 142 | }; | |
| 143 | ||
| 144 | const cmd_fns = [_]CmdFn{ | |
| 145 | CmdFn{ | |
| 146 | .name = "one", | |
| 147 | .func = one, | |
| 148 | }, | |
| 149 | CmdFn{ | |
| 150 | .name = "two", | |
| 151 | .func = two, | |
| 152 | }, | |
| 153 | CmdFn{ | |
| 154 | .name = "three", | |
| 155 | .func = three, | |
| 156 | }, | |
| 157 | }; | |
| 158 | fn one(value: i32) i32 { | |
| 159 | return value + 1; | |
| 160 | } | |
| 161 | fn two(value: i32) i32 { | |
| 162 | return value + 2; | |
| 163 | } | |
| 164 | fn three(value: i32) i32 { | |
| 165 | return value + 3; | |
| 166 | } | |
| 167 | ||
| 168 | fn performFn(comptime prefix_char: u8, start_value: i32) i32 { | |
| 169 | var result: i32 = start_value; | |
| 170 | comptime var i = 0; | |
| 171 | inline while (i < cmd_fns.len) : (i += 1) { | |
| 172 | if (cmd_fns[i].name[0] == prefix_char) { | |
| 173 | result = cmd_fns[i].func(result); | |
| 174 | } | |
| 175 | } | |
| 176 | return result; | |
| 177 | } | |
| 178 | ||
| 179 | test "comptime iterate over fn ptr list" { | |
| 180 | try expect(performFn('t', 1) == 6); | |
| 181 | try expect(performFn('o', 0) == 1); | |
| 182 | try expect(performFn('w', 99) == 99); | |
| 183 | } | |
| 184 | ||
| 185 | test "eval @setFloatMode at compile-time" { | |
| 186 | const result = comptime fnWithFloatMode(); | |
| 187 | try expect(result == 1234.0); | |
| 188 | } | |
| 189 | ||
| 190 | fn fnWithFloatMode() f32 { | |
| 191 | @setFloatMode(std.builtin.FloatMode.Strict); | |
| 192 | return 1234.0; | |
| 193 | } | |
| 194 | ||
| 195 | const SimpleStruct = struct { | |
| 196 | field: i32, | |
| 197 | ||
| 198 | fn method(self: *const SimpleStruct) i32 { | |
| 199 | return self.field + 3; | |
| 200 | } | |
| 201 | }; | |
| 202 | ||
| 203 | var simple_struct = SimpleStruct{ .field = 1234 }; | |
| 204 | ||
| 205 | const bound_fn = simple_struct.method; | |
| 206 | ||
| 207 | test "call method on bound fn referring to var instance" { | |
| 208 | try expect(bound_fn() == 1237); | |
| 209 | } | |
| 210 | ||
| 211 | test "ptr to local array argument at comptime" { | |
| 212 | comptime { | |
| 213 | var bytes: [10]u8 = undefined; | |
| 214 | modifySomeBytes(bytes[0..]); | |
| 215 | try expect(bytes[0] == 'a'); | |
| 216 | try expect(bytes[9] == 'b'); | |
| 217 | } | |
| 218 | } | |
| 219 | ||
| 220 | fn modifySomeBytes(bytes: []u8) void { | |
| 221 | bytes[0] = 'a'; | |
| 222 | bytes[9] = 'b'; | |
| 223 | } | |
| 224 | ||
| 225 | test "comparisons 0 <= uint and 0 > uint should be comptime" { | |
| 226 | testCompTimeUIntComparisons(1234); | |
| 227 | } | |
| 228 | fn testCompTimeUIntComparisons(x: u32) void { | |
| 229 | if (!(0 <= x)) { | |
| 230 | @compileError("this condition should be comptime known"); | |
| 231 | } | |
| 232 | if (0 > x) { | |
| 233 | @compileError("this condition should be comptime known"); | |
| 234 | } | |
| 235 | if (!(x >= 0)) { | |
| 236 | @compileError("this condition should be comptime known"); | |
| 237 | } | |
| 238 | if (x < 0) { | |
| 239 | @compileError("this condition should be comptime known"); | |
| 240 | } | |
| 241 | } | |
| 242 | ||
| 243 | test "const ptr to variable data changes at runtime" { | |
| 244 | try expect(foo_ref.name[0] == 'a'); | |
| 245 | foo_ref.name = "b"; | |
| 246 | try expect(foo_ref.name[0] == 'b'); | |
| 247 | } | |
| 248 | ||
| 249 | const Foo = struct { | |
| 250 | name: []const u8, | |
| 251 | }; | |
| 252 | ||
| 253 | var foo_contents = Foo{ .name = "a" }; | |
| 254 | const foo_ref = &foo_contents; | |
| 255 | ||
| 256 | test "create global array with for loop" { | |
| 257 | try expect(global_array[5] == 5 * 5); | |
| 258 | try expect(global_array[9] == 9 * 9); | |
| 259 | } | |
| 260 | ||
| 261 | const global_array = x: { | |
| 262 | var result: [10]usize = undefined; | |
| 263 | for (result) |*item, index| { | |
| 264 | item.* = index * index; | |
| 265 | } | |
| 266 | break :x result; | |
| 267 | }; | |
| 268 | ||
| 269 | const hi1 = "hi"; | |
| 270 | const hi2 = hi1; | |
| 271 | test "const global shares pointer with other same one" { | |
| 272 | try assertEqualPtrs(&hi1[0], &hi2[0]); | |
| 273 | comptime try expect(&hi1[0] == &hi2[0]); | |
| 274 | } | |
| 275 | fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) !void { | |
| 276 | try expect(ptr1 == ptr2); | |
| 277 | } | |
| 278 | ||
| 279 | test "@setEvalBranchQuota" { | |
| 280 | comptime { | |
| 281 | // 1001 for the loop and then 1 more for the expect fn call | |
| 282 | @setEvalBranchQuota(1002); | |
| 283 | var i = 0; | |
| 284 | var sum = 0; | |
| 285 | while (i < 1001) : (i += 1) { | |
| 286 | sum += i; | |
| 287 | } | |
| 288 | try expect(sum == 500500); | |
| 289 | } | |
| 290 | } | |
| 291 | ||
| 292 | test "float literal at compile time not lossy" { | |
| 293 | try expect(16777216.0 + 1.0 == 16777217.0); | |
| 294 | try expect(9007199254740992.0 + 1.0 == 9007199254740993.0); | |
| 295 | } | |
| 296 | ||
| 297 | test "f32 at compile time is lossy" { | |
| 298 | try expect(@as(f32, 1 << 24) + 1 == 1 << 24); | |
| 299 | } | |
| 300 | ||
| 301 | test "f64 at compile time is lossy" { | |
| 302 | try expect(@as(f64, 1 << 53) + 1 == 1 << 53); | |
| 303 | } | |
| 304 | ||
| 305 | test "f128 at compile time is lossy" { | |
| 306 | try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); | |
| 307 | } | |
| 308 | ||
| 309 | test { | |
| 310 | comptime try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192); | |
| 311 | } | |
| 312 | ||
| 313 | pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { | |
| 314 | _ = field_name; | |
| 315 | return struct { | |
| 316 | pub const Node = struct {}; | |
| 317 | }; | |
| 318 | } | |
| 319 | ||
| 320 | test "string literal used as comptime slice is memoized" { | |
| 321 | const a = "link"; | |
| 322 | const b = "link"; | |
| 323 | comptime try expect(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); | |
| 324 | comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); | |
| 325 | } | |
| 326 | ||
| 327 | test "comptime slice of undefined pointer of length 0" { | |
| 328 | const slice1 = @as([*]i32, undefined)[0..0]; | |
| 329 | try expect(slice1.len == 0); | |
| 330 | const slice2 = @as([*]i32, undefined)[100..100]; | |
| 331 | try expect(slice2.len == 0); | |
| 332 | } | |
| 333 | ||
| 334 | fn copyWithPartialInline(s: []u32, b: []u8) void { | |
| 335 | comptime var i: usize = 0; | |
| 336 | inline while (i < 4) : (i += 1) { | |
| 337 | s[i] = 0; | |
| 338 | s[i] |= @as(u32, b[i * 4 + 0]) << 24; | |
| 339 | s[i] |= @as(u32, b[i * 4 + 1]) << 16; | |
| 340 | s[i] |= @as(u32, b[i * 4 + 2]) << 8; | |
| 341 | s[i] |= @as(u32, b[i * 4 + 3]) << 0; | |
| 342 | } | |
| 343 | } | |
| 344 | ||
| 345 | test "binary math operator in partially inlined function" { | |
| 346 | var s: [4]u32 = undefined; | |
| 347 | var b: [16]u8 = undefined; | |
| 348 | ||
| 349 | for (b) |*r, i| | |
| 350 | r.* = @intCast(u8, i + 1); | |
| 351 | ||
| 352 | copyWithPartialInline(s[0..], b[0..]); | |
| 353 | try expect(s[0] == 0x1020304); | |
| 354 | try expect(s[1] == 0x5060708); | |
| 355 | try expect(s[2] == 0x90a0b0c); | |
| 356 | try expect(s[3] == 0xd0e0f10); | |
| 357 | } | |
| 358 | ||
| 359 | test "comptime function with the same args is memoized" { | |
| 360 | comptime { | |
| 361 | try expect(MakeType(i32) == MakeType(i32)); | |
| 362 | try expect(MakeType(i32) != MakeType(f64)); | |
| 363 | } | |
| 364 | } | |
| 365 | ||
| 366 | fn MakeType(comptime T: type) type { | |
| 367 | return struct { | |
| 368 | field: T, | |
| 369 | }; | |
| 370 | } | |
| 371 | ||
| 372 | test "comptime function with mutable pointer is not memoized" { | |
| 373 | comptime { | |
| 374 | var x: i32 = 1; | |
| 375 | const ptr = &x; | |
| 376 | increment(ptr); | |
| 377 | increment(ptr); | |
| 378 | try expect(x == 3); | |
| 379 | } | |
| 380 | } | |
| 381 | ||
| 382 | fn increment(value: *i32) void { | |
| 383 | value.* += 1; | |
| 384 | } | |
| 385 | ||
| 386 | fn generateTable(comptime T: type) [1010]T { | |
| 387 | var res: [1010]T = undefined; | |
| 388 | var i: usize = 0; | |
| 389 | while (i < 1010) : (i += 1) { | |
| 390 | res[i] = @intCast(T, i); | |
| 391 | } | |
| 392 | return res; | |
| 393 | } | |
| 394 | ||
| 395 | fn doesAlotT(comptime T: type, value: usize) T { | |
| 396 | @setEvalBranchQuota(5000); | |
| 397 | const table = comptime blk: { | |
| 398 | break :blk generateTable(T); | |
| 399 | }; | |
| 400 | return table[value]; | |
| 401 | } | |
| 402 | ||
| 403 | test "@setEvalBranchQuota at same scope as generic function call" { | |
| 404 | try expect(doesAlotT(u32, 2) == 2); | |
| 405 | } | |
| 406 | ||
| 407 | test "comptime slice of slice preserves comptime var" { | |
| 408 | comptime { | |
| 409 | var buff: [10]u8 = undefined; | |
| 410 | buff[0..][0..][0] = 1; | |
| 411 | try expect(buff[0..][0..][0] == 1); | |
| 412 | } | |
| 413 | } | |
| 414 | ||
| 415 | test "comptime slice of pointer preserves comptime var" { | |
| 416 | comptime { | |
| 417 | var buff: [10]u8 = undefined; | |
| 418 | var a = @ptrCast([*]u8, &buff); | |
| 419 | a[0..1][0] = 1; | |
| 420 | try expect(buff[0..][0..][0] == 1); | |
| 421 | } | |
| 422 | } | |
| 423 | ||
| 424 | const SingleFieldStruct = struct { | |
| 425 | x: i32, | |
| 426 | ||
| 427 | fn read_x(self: *const SingleFieldStruct) i32 { | |
| 428 | return self.x; | |
| 429 | } | |
| 430 | }; | |
| 431 | test "const ptr to comptime mutable data is not memoized" { | |
| 432 | comptime { | |
| 433 | var foo = SingleFieldStruct{ .x = 1 }; | |
| 434 | try expect(foo.read_x() == 1); | |
| 435 | foo.x = 2; | |
| 436 | try expect(foo.read_x() == 2); | |
| 437 | } | |
| 438 | } | |
| 439 | ||
| 440 | test "array concat of slices gives slice" { | |
| 441 | comptime { | |
| 442 | var a: []const u8 = "aoeu"; | |
| 443 | var b: []const u8 = "asdf"; | |
| 444 | const c = a ++ b; | |
| 445 | try expect(std.mem.eql(u8, c, "aoeuasdf")); | |
| 446 | } | |
| 447 | } | |
| 448 | ||
| 449 | test "comptime shlWithOverflow" { | |
| 450 | const ct_shifted: u64 = comptime amt: { | |
| 451 | var amt = @as(u64, 0); | |
| 452 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | |
| 453 | break :amt amt; | |
| 454 | }; | |
| 455 | ||
| 456 | const rt_shifted: u64 = amt: { | |
| 457 | var amt = @as(u64, 0); | |
| 458 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | |
| 459 | break :amt amt; | |
| 460 | }; | |
| 461 | ||
| 462 | try expect(ct_shifted == rt_shifted); | |
| 463 | } | |
| 464 | ||
| 465 | test "comptime shl" { | |
| 466 | var a: u128 = 3; | |
| 467 | var b: u7 = 63; | |
| 468 | var c: u128 = 3 << 63; | |
| 469 | try expectEqual(a << b, c); | |
| 470 | } | |
| 471 | ||
| 472 | test "runtime 128 bit integer division" { | |
| 473 | var a: u128 = 152313999999999991610955792383; | |
| 474 | var b: u128 = 10000000000000000000; | |
| 475 | var c = a / b; | |
| 476 | try expect(c == 15231399999); | |
| 477 | } | |
| 478 | ||
| 479 | pub const Info = struct { | |
| 480 | version: u8, | |
| 481 | }; | |
| 482 | ||
| 483 | pub const diamond_info = Info{ .version = 0 }; | |
| 484 | ||
| 485 | test "comptime modification of const struct field" { | |
| 486 | comptime { | |
| 487 | var res = diamond_info; | |
| 488 | res.version = 1; | |
| 489 | try expect(diamond_info.version == 0); | |
| 490 | try expect(res.version == 1); | |
| 491 | } | |
| 492 | } | |
| 493 | ||
| 494 | test "slice of type" { | |
| 495 | comptime { | |
| 496 | var types_array = [_]type{ i32, f64, type }; | |
| 497 | for (types_array) |T, i| { | |
| 498 | switch (i) { | |
| 499 | 0 => try expect(T == i32), | |
| 500 | 1 => try expect(T == f64), | |
| 501 | 2 => try expect(T == type), | |
| 502 | else => unreachable, | |
| 503 | } | |
| 504 | } | |
| 505 | for (types_array[0..]) |T, i| { | |
| 506 | switch (i) { | |
| 507 | 0 => try expect(T == i32), | |
| 508 | 1 => try expect(T == f64), | |
| 509 | 2 => try expect(T == type), | |
| 510 | else => unreachable, | |
| 511 | } | |
| 512 | } | |
| 513 | } | |
| 514 | } | |
| 515 | ||
| 516 | const Wrapper = struct { | |
| 517 | T: type, | |
| 518 | }; | |
| 519 | ||
| 520 | fn wrap(comptime T: type) Wrapper { | |
| 521 | return Wrapper{ .T = T }; | |
| 522 | } | |
| 523 | ||
| 524 | test "function which returns struct with type field causes implicit comptime" { | |
| 525 | const ty = wrap(i32).T; | |
| 526 | try expect(ty == i32); | |
| 527 | } | |
| 528 | ||
| 529 | test "call method with comptime pass-by-non-copying-value self parameter" { | |
| 530 | const S = struct { | |
| 531 | a: u8, | |
| 532 | ||
| 533 | fn b(comptime s: @This()) u8 { | |
| 534 | return s.a; | |
| 535 | } | |
| 536 | }; | |
| 537 | ||
| 538 | const s = S{ .a = 2 }; | |
| 539 | var b = s.b(); | |
| 540 | try expect(b == 2); | |
| 541 | } | |
| 542 | ||
| 543 | test "@tagName of @typeInfo" { | |
| 544 | const str = @tagName(@typeInfo(u8)); | |
| 545 | try expect(std.mem.eql(u8, str, "Int")); | |
| 546 | } | |
| 547 | ||
| 548 | test "setting backward branch quota just before a generic fn call" { | |
| 549 | @setEvalBranchQuota(1001); | |
| 550 | loopNTimes(1001); | |
| 551 | } | |
| 552 | ||
| 553 | fn loopNTimes(comptime n: usize) void { | |
| 554 | comptime var i = 0; | |
| 555 | inline while (i < n) : (i += 1) {} | |
| 556 | } | |
| 557 | ||
| 558 | test "variable inside inline loop that has different types on different iterations" { | |
| 559 | try testVarInsideInlineLoop(.{ true, @as(u32, 42) }); | |
| 560 | } | |
| 561 | ||
| 562 | fn testVarInsideInlineLoop(args: anytype) !void { | |
| 563 | comptime var i = 0; | |
| 564 | inline while (i < args.len) : (i += 1) { | |
| 565 | const x = args[i]; | |
| 566 | if (i == 0) try expect(x); | |
| 567 | if (i == 1) try expect(x == 42); | |
| 568 | } | |
| 569 | } | |
| 570 | ||
| 571 | test "inline for with same type but different values" { | |
| 572 | var res: usize = 0; | |
| 573 | inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| { | |
| 574 | var a: T = undefined; | |
| 575 | res += a.len; | |
| 576 | } | |
| 577 | try expect(res == 5); | |
| 578 | } | |
| 579 | ||
| 580 | test "refer to the type of a generic function" { | |
| 581 | const Func = fn (type) void; | |
| 582 | const f: Func = doNothingWithType; | |
| 583 | f(i32); | |
| 584 | } | |
| 585 | ||
| 586 | fn doNothingWithType(comptime T: type) void { | |
| 587 | _ = T; | |
| 588 | } | |
| 589 | ||
| 590 | test "zero extend from u0 to u1" { | |
| 591 | var zero_u0: u0 = 0; | |
| 592 | var zero_u1: u1 = zero_u0; | |
| 593 | try expect(zero_u1 == 0); | |
| 594 | } | |
| 595 | ||
| 596 | test "bit shift a u1" { | |
| 597 | var x: u1 = 1; | |
| 598 | var y = x << 0; | |
| 599 | try expect(y == 1); | |
| 600 | } | |
| 601 | ||
| 602 | test "comptime pointer cast array and then slice" { | |
| 603 | const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; | |
| 604 | ||
| 605 | const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); | |
| 606 | const sliceA: []const u8 = ptrA[0..2]; | |
| 607 | ||
| 608 | const ptrB: [*]const u8 = &array; | |
| 609 | const sliceB: []const u8 = ptrB[0..2]; | |
| 610 | ||
| 611 | try expect(sliceA[1] == 2); | |
| 612 | try expect(sliceB[1] == 2); | |
| 613 | } | |
| 614 | ||
| 615 | test "slice bounds in comptime concatenation" { | |
| 616 | const bs = comptime blk: { | |
| 617 | const b = "........1........"; | |
| 618 | break :blk b[8..9]; | |
| 619 | }; | |
| 620 | const str = "" ++ bs; | |
| 621 | try expect(str.len == 1); | |
| 622 | try expect(std.mem.eql(u8, str, "1")); | |
| 623 | ||
| 624 | const str2 = bs ++ ""; | |
| 625 | try expect(str2.len == 1); | |
| 626 | try expect(std.mem.eql(u8, str2, "1")); | |
| 627 | } | |
| 628 | ||
| 629 | test "comptime bitwise operators" { | |
| 630 | comptime { | |
| 631 | try expect(3 & 1 == 1); | |
| 632 | try expect(3 & -1 == 3); | |
| 633 | try expect(-3 & -1 == -3); | |
| 634 | try expect(3 | -1 == -1); | |
| 635 | try expect(-3 | -1 == -1); | |
| 636 | try expect(3 ^ -1 == -4); | |
| 637 | try expect(-3 ^ -1 == 2); | |
| 638 | try expect(~@as(i8, -1) == 0); | |
| 639 | try expect(~@as(i128, -1) == 0); | |
| 640 | try expect(18446744073709551615 & 18446744073709551611 == 18446744073709551611); | |
| 641 | try expect(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); | |
| 642 | try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff); | |
| 643 | } | |
| 644 | } | |
| 645 | ||
| 646 | test "*align(1) u16 is the same as *align(1:0:2) u16" { | |
| 647 | comptime { | |
| 648 | try expect(*align(1:0:2) u16 == *align(1) u16); | |
| 649 | try expect(*align(2:0:2) u16 == *u16); | |
| 650 | } | |
| 651 | } | |
| 652 | ||
| 653 | test "array concatenation forces comptime" { | |
| 654 | var a = oneItem(3) ++ oneItem(4); | |
| 655 | try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 })); | |
| 656 | } | |
| 657 | ||
| 658 | test "array multiplication forces comptime" { | |
| 659 | var a = oneItem(3) ** scalar(2); | |
| 660 | try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 })); | |
| 661 | } | |
| 662 | ||
| 663 | fn oneItem(x: i32) [1]i32 { | |
| 664 | return [_]i32{x}; | |
| 665 | } | |
| 666 | ||
| 667 | fn scalar(x: u32) u32 { | |
| 668 | return x; | |
| 669 | } | |
| 670 | ||
| 671 | test "comptime assign int to optional int" { | |
| 672 | comptime { | |
| 673 | var x: ?i32 = null; | |
| 674 | x = 2; | |
| 675 | x.? *= 10; | |
| 676 | try expectEqual(20, x.?); | |
| 677 | } | |
| 678 | } | |
| 679 | ||
| 680 | test "return 0 from function that has u0 return type" { | |
| 681 | const S = struct { | |
| 682 | fn foo_zero() u0 { | |
| 683 | return 0; | |
| 684 | } | |
| 685 | }; | |
| 686 | comptime { | |
| 687 | if (S.foo_zero() != 0) { | |
| 688 | @compileError("test failed"); | |
| 689 | } | |
| 690 | } | |
| 691 | } | |
| 692 | ||
| 693 | test "two comptime calls with array default initialized to undefined" { | |
| 694 | const S = struct { | |
| 695 | const CrossTarget = struct { | |
| 696 | dynamic_linker: DynamicLinker = DynamicLinker{}, | |
| 697 | ||
| 698 | pub fn parse() void { | |
| 699 | var result: CrossTarget = .{}; | |
| 700 | result.getCpuArch(); | |
| 701 | } | |
| 702 | ||
| 703 | pub fn getCpuArch(self: CrossTarget) void { | |
| 704 | _ = self; | |
| 705 | } | |
| 706 | }; | |
| 707 | ||
| 708 | const DynamicLinker = struct { | |
| 709 | buffer: [255]u8 = undefined, | |
| 710 | }; | |
| 711 | }; | |
| 712 | ||
| 713 | comptime { | |
| 714 | S.CrossTarget.parse(); | |
| 715 | S.CrossTarget.parse(); | |
| 716 | } | |
| 717 | } |