diff --git a/doc/docgen.zig b/doc/docgen.zig index 3ec961802c..82fafe2b64 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -539,12 +539,15 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc { } else if (mem.eql(u8, tag_name, "code_begin")) { _ = try eatToken(tokenizer, Token.Id.Separator); const code_kind_tok = try eatToken(tokenizer, Token.Id.TagContent); - var name: []const u8 = "test"; + _ = try eatToken(tokenizer, Token.Id.Separator); + const name_tok = try eatToken(tokenizer, Token.Id.TagContent); + const name = tokenizer.buffer[name_tok.start..name_tok.end]; + var error_str: []const u8 = ""; const maybe_sep = tokenizer.next(); switch (maybe_sep.id) { Token.Id.Separator => { - const name_tok = try eatToken(tokenizer, Token.Id.TagContent); - name = tokenizer.buffer[name_tok.start..name_tok.end]; + const error_tok = try eatToken(tokenizer, Token.Id.TagContent); + error_str = tokenizer.buffer[error_tok.start..error_tok.end]; _ = try eatToken(tokenizer, Token.Id.BracketClose); }, Token.Id.BracketClose => {}, @@ -562,16 +565,13 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc { } else if (mem.eql(u8, code_kind_str, "test")) { code_kind_id = Code.Id.Test; } else if (mem.eql(u8, code_kind_str, "test_err")) { - code_kind_id = Code.Id{ .TestError = name }; - name = "test"; + code_kind_id = Code.Id{ .TestError = error_str }; } else if (mem.eql(u8, code_kind_str, "test_safety")) { - code_kind_id = Code.Id{ .TestSafety = name }; - name = "test"; + code_kind_id = Code.Id{ .TestSafety = error_str }; } else if (mem.eql(u8, code_kind_str, "obj")) { code_kind_id = Code.Id{ .Obj = null }; } else if (mem.eql(u8, code_kind_str, "obj_err")) { - code_kind_id = Code.Id{ .Obj = name }; - name = "test"; + code_kind_id = Code.Id{ .Obj = error_str }; } else if (mem.eql(u8, code_kind_str, "lib")) { code_kind_id = Code.Id.Lib; } else if (mem.eql(u8, code_kind_str, "syntax")) { diff --git a/doc/langref.html.in b/doc/langref.html.in index bcee4276ea..d305460d66 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -1039,7 +1039,7 @@ pub fn main() void {
Code written within one or more {#syntax#}test{#endsyntax#} declarations can be used to ensure behavior meets expectations:
- {#code_begin|test|introducing_zig_test#} + {#code_begin|test|testing_introduction#} const std = @import("std"); test "expect addOne adds one to 41" { @@ -1124,13 +1124,13 @@ fn addOne(number: i32) i32 { syntax. This syntax tells the compiler to ignore the result of the expression on the right side of the assignment operator. - {#code_begin|test|testdecl_container_top_level#} + {#code_begin|test|testing_nested_container_tests#} const std = @import("std"); const expect = std.testing.expect; // Imported source file tests will run when referenced from a top-level test declaration. // The next line alone does not cause "introducing_zig_test.zig" tests to run. -const imported_file = @import("introducing_zig_test.zig"); +const imported_file = @import("testing_introduction.zig"); test { // To run nested container tests, either, call `refAllDecls` which will @@ -1143,7 +1143,7 @@ test { // The `_ = C;` syntax is a no-op reference to the identifier `C`. _ = S; _ = U; - _ = @import("introducing_zig_test.zig"); + _ = @import("testing_introduction.zig"); } const S = struct { @@ -1184,7 +1184,7 @@ const U = union { // U is referenced by the file's top-level test declaration When a test returns an error, the test is considered a failure and its {#link|error return trace|Error Return Traces#} is output to standard error. The total number of failures will be reported after all tests have run. - {#code_begin|test_err#} + {#code_begin|test_err|testing_failure#} const std = @import("std"); test "expect this to fail" { @@ -1208,7 +1208,7 @@ test "expect this to succeed" { {#syntax#}error.SkipZigTest{#endsyntax#} and the default test runner will consider the test as being skipped. The total number of skipped tests will be reported after all tests have run. - {#code_begin|test#} + {#code_begin|test|testing_skip#} test "this will be skipped" { return error.SkipZigTest; } @@ -1221,7 +1221,7 @@ test "this will be skipped" { {#syntax#}std.testing.allocator{#endsyntax#}, the default test runner will report any leaks that are found from using the testing allocator: - {#code_begin|test_err|1 tests leaked memory#} + {#code_begin|test_err|testing_detect_leak|1 tests leaked memory#} const std = @import("std"); test "detect leak" { @@ -1239,7 +1239,7 @@ test "detect leak" { Use the {#link|compile variable|Compile Variables#} {#syntax#}@import("builtin").is_test{#endsyntax#} to detect a test build: - {#code_begin|test|detect_test#} + {#code_begin|test|testing_detect_test#} const std = @import("std"); const builtin = @import("builtin"); const expect = std.testing.expect; @@ -1264,7 +1264,7 @@ fn isATest() bool { you create tests. In addition to theexpect
function, this document uses a couple of more functions
as exemplified here:
- {#code_begin|test|testing_functions#}
+ {#code_begin|test|testing_namespace#}
const std = @import("std");
test "expectEqual demo" {
@@ -1319,7 +1319,7 @@ test "expectError demo" {
If a name that does not fit these requirements is needed, such as for linking with external libraries, the {#syntax#}@""{#endsyntax#} syntax may be used.
- {#code_begin|syntax#} + {#code_begin|syntax|identifiers#} const @"identifier with spaces in it" = 0xff; const @"1SmallStep4Man" = 112358; @@ -1342,7 +1342,7 @@ const color: Color = .@"really red"; {#link|comptime#}. If a container level variable is {#syntax#}const{#endsyntax#} then its value is {#syntax#}comptime{#endsyntax#}-known, otherwise it is runtime-known. - {#code_begin|test|container_level_variables#} + {#code_begin|test|test_container_level_variables#} var y: i32 = add(10, x); const x: i32 = add(12, 34); @@ -1361,7 +1361,7 @@ const expect = std.testing.expect;Container level variables may be declared inside a {#link|struct#}, {#link|union#}, {#link|enum#}, or {#link|opaque#}:
- {#code_begin|test|namespaced_container_level_variable#} + {#code_begin|test|test_namespaced_container_level_variable#} const std = @import("std"); const expect = std.testing.expect; @@ -1385,7 +1385,7 @@ fn foo() i32 {It is also possible to have local variables with static lifetime by using containers inside functions.
- {#code_begin|test|static_local_variable#} + {#code_begin|test|test_static_local_variable#} const std = @import("std"); const expect = std.testing.expect; @@ -1414,7 +1414,7 @@ fn foo() i32 { {#header_open|Thread Local Variables#}A variable may be specified to be a thread-local variable using the {#syntax#}threadlocal{#endsyntax#} keyword:
- {#code_begin|test|tls#} + {#code_begin|test|test_thread_local_variables#} const std = @import("std"); const assert = std.debug.assert; @@ -1458,7 +1458,7 @@ fn testTls() void { All variables declared in a {#syntax#}comptime{#endsyntax#} expression are implicitly {#syntax#}comptime{#endsyntax#} variables. - {#code_begin|test|comptime_vars#} + {#code_begin|test|test_comptime_variables#} const std = @import("std"); const expect = std.testing.expect; @@ -1582,7 +1582,7 @@ const nan = std.math.nan(f128); {#header_open|Floating Point Operations#}By default floating point operations use {#syntax#}Strict{#endsyntax#} mode, but you can switch to {#syntax#}Optimized{#endsyntax#} mode on a per-block basis:
- {#code_begin|obj|foo#} + {#code_begin|obj|float_mode_obj#} {#code_release_fast#} {#code_disable_cache#} const std = @import("std"); @@ -1600,8 +1600,8 @@ export fn foo_optimized(x: f64) f64 {For this test we have to separate code into two object files - otherwise the optimizer figures out all the values at compile-time, which operates in strict mode.
- {#code_begin|exe|float_mode#} - {#code_link_object|foo#} + {#code_begin|exe|float_mode_exe#} + {#code_link_object|float_mode_obj#} const print = @import("std").debug.print; extern fn foo_strict(x: f64) f64; @@ -2326,7 +2326,7 @@ or {#header_close#} {#header_close#} {#header_open|Arrays#} - {#code_begin|test|arrays#} + {#code_begin|test|test_arrays#} const expect = @import("std").testing.expect; const assert = @import("std").debug.assert; const mem = @import("std").mem; @@ -2437,7 +2437,7 @@ test "array initialization with function calls" {Multidimensional arrays can be created by nesting arrays:
- {#code_begin|test|multidimensional#} + {#code_begin|test|test_multidimensional_arrays#} const std = @import("std"); const expect = std.testing.expect; @@ -2468,7 +2468,7 @@ test "multidimensional arrays" { The syntax {#syntax#}[N:x]T{#endsyntax#} describes an array which has a sentinel element of value {#syntax#}x{#endsyntax#} at the index corresponding to {#syntax#}len{#endsyntax#}. - {#code_begin|test|null_terminated_array#} + {#code_begin|test|test_null_terminated_array#} const std = @import("std"); const expect = std.testing.expect; @@ -2521,7 +2521,7 @@ test "null terminated array" { although small powers of two (2-64) are most typical. Note that excessively long vector lengths (e.g. 2^20) may result in compiler crashes on current versions of Zig. - {#code_begin|test|vector_example#} + {#code_begin|test|test_vector#} const std = @import("std"); const expectEqual = std.testing.expectEqual; @@ -2609,7 +2609,7 @@ test "Conversion between vectors, arrays, and slices" {Use {#syntax#}&x{#endsyntax#} to obtain a single-item pointer:
- {#code_begin|test|single_item_pointer_test#} + {#code_begin|test|test_single_item_pointer#} const expect = @import("std").testing.expect; test "address of syntax" { @@ -2647,7 +2647,7 @@ test "pointer array access" {Zig supports pointer arithmetic. It's better to assign the pointer to {#syntax#}[*]T{#endsyntax#} and increment that variable. For example, directly incrementing the pointer from a slice will corrupt it.
- {#code_begin|test|pointer_arthemtic#} + {#code_begin|test|test_pointer_arithmetic#} const expect = @import("std").testing.expect; test "pointer arithmetic with many-item pointer" { @@ -2683,7 +2683,7 @@ test "pointer arithmetic with slices" { against this kind of undefined behavior. This is one reason we prefer slices to pointers. - {#code_begin|test|slice_bounds#} + {#code_begin|test|test_slice_bounds#} const expect = @import("std").testing.expect; test "pointer slicing" { @@ -2699,7 +2699,7 @@ test "pointer slicing" { {#code_end#}Pointers work at compile-time too, as long as the code does not depend on an undefined memory layout:
- {#code_begin|test|comptime_pointers#} + {#code_begin|test|test_comptime_pointers#} const expect = @import("std").testing.expect; test "comptime pointers" { @@ -2714,7 +2714,7 @@ test "comptime pointers" { {#code_end#}To convert an integer address into a pointer, use {#syntax#}@intToPtr{#endsyntax#}. To convert a pointer to an integer, use {#syntax#}@ptrToInt{#endsyntax#}:
- {#code_begin|test|integer_pointer_conversion#} + {#code_begin|test|test_integer_pointer_conversion#} const expect = @import("std").testing.expect; test "@ptrToInt and @intToPtr" { @@ -2726,7 +2726,7 @@ test "@ptrToInt and @intToPtr" { {#code_end#}Zig is able to preserve memory addresses in comptime code, as long as the pointer is never dereferenced:
- {#code_begin|test|comptime_pointer_conversion#} + {#code_begin|test|test_comptime_pointer_conversion#} const expect = @import("std").testing.expect; test "comptime @intToPtr" { @@ -2746,7 +2746,7 @@ test "comptime @intToPtr" { should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}. In the following code, loads and stores with {#syntax#}mmio_ptr{#endsyntax#} are guaranteed to all happen and in the same order as in source code: - {#code_begin|test|volatile#} + {#code_begin|test|test_volatile#} const expect = @import("std").testing.expect; test "volatile" { @@ -2765,7 +2765,7 @@ test "volatile" { operation that Zig cannot protect you against. Use {#syntax#}@ptrCast{#endsyntax#} only when other conversions are not possible. - {#code_begin|test|pointer_casting#} + {#code_begin|test|test_pointer_casting#} const std = @import("std"); const expect = std.testing.expect; @@ -2803,7 +2803,7 @@ test "pointer child type" { In Zig, a pointer type has an alignment value. If the value is equal to the alignment of the underlying type, it can be omitted from the type: - {#code_begin|test|variable_alignment#} + {#code_begin|test|test_variable_alignment#} const std = @import("std"); const builtin = @import("builtin"); const expect = std.testing.expect; @@ -2826,7 +2826,7 @@ test "variable alignment" { You can specify alignment on variables and functions. If you do this, then pointers to them get the specified alignment: - {#code_begin|test|variable_func_alignment#} + {#code_begin|test|test_variable_func_alignment#} const expect = @import("std").testing.expect; var foo: u8 align(4) = 100; @@ -2860,7 +2860,7 @@ test "function alignment" { pointer into a more aligned pointer. This is a no-op at runtime, but inserts a {#link|safety check|Incorrect Pointer Alignment#}: - {#code_begin|test_safety|incorrect alignment#} + {#code_begin|test_safety|test_incorrect_pointer_alignment|incorrect alignment#} const std = @import("std"); test "pointer alignment safety" { @@ -2885,7 +2885,7 @@ fn foo(bytes: []u8) u32 { did not have the {#syntax#}allowzero{#endsyntax#} attribute, this would be a {#link|Pointer Cast Invalid Null#} panic: - {#code_begin|test|allowzero#} + {#code_begin|test|test_allowzero#} const std = @import("std"); const expect = std.testing.expect; @@ -2903,7 +2903,7 @@ test "allowzero" { has a length determined by a sentinel value. This provides protection against buffer overflow and overreads. - {#code_begin|exe_build_err#} + {#code_begin|exe_build_err|sentinel-terminated_pointer#} {#link_libc#} const std = @import("std"); @@ -2923,7 +2923,7 @@ pub fn main() anyerror!void { {#header_close#} {#header_open|Slices#} - {#code_begin|test_safety|index out of bounds#} + {#code_begin|test_safety|test_basic_slices|index out of bounds#} const expect = @import("std").testing.expect; test "basic slices" { @@ -2958,7 +2958,7 @@ test "basic slices" { } {#code_end#}This is one reason we prefer slices to pointers.
- {#code_begin|test|slices#} + {#code_begin|test|test_slices#} const std = @import("std"); const expect = std.testing.expect; const mem = std.mem; @@ -3019,7 +3019,7 @@ test "slice pointer" { guarantee that there are no sentinel elements before that. Sentinel-terminated slices allow element access to the {#syntax#}len{#endsyntax#} index. - {#code_begin|test|null_terminated_slice#} + {#code_begin|test|test_null_terminated_slice#} const std = @import("std"); const expect = std.testing.expect; @@ -3035,7 +3035,7 @@ test "null terminated slice" { {#syntax#}data[start..end :x]{#endsyntax#}, where {#syntax#}data{#endsyntax#} is a many-item pointer, array or slice and {#syntax#}x{#endsyntax#} is the sentinel value. - {#code_begin|test|null_terminated_slicing#} + {#code_begin|test|test_null_terminated_slicing#} const std = @import("std"); const expect = std.testing.expect; @@ -3052,7 +3052,7 @@ test "null terminated slicing" { Sentinel-terminated slicing asserts that the element in the sentinel position of the backing data is actually the sentinel value. If this is not the case, safety-protected {#link|Undefined Behavior#} results. - {#code_begin|test_safety|sentinel mismatch#} + {#code_begin|test_safety|test_sentinel_mismatch|sentinel mismatch#} const std = @import("std"); const expect = std.testing.expect; @@ -3074,7 +3074,7 @@ test "sentinel mismatch" { {#header_close#} {#header_open|struct#} - {#code_begin|test|structs#} + {#code_begin|test|test_structs#} // Declare a struct. // Zig gives no guarantees about the order of fields and the size of // the struct but the fields are guaranteed to be ABI-aligned. @@ -3223,7 +3223,7 @@ test "linked list" { Each struct field may have an expression indicating the default field value. Such expressions are executed at {#link|comptime#}, and allow the field to be omitted in a struct literal expression: - {#code_begin|test|default_field_values#} + {#code_begin|test|test_struct_default_field_values#} const Foo = struct { a: i32 = 1234, b: i32, @@ -3272,7 +3272,7 @@ test "default struct initialization fields" { in a {#link|@bitCast#} or a {#link|@ptrCast#} to reinterpret memory. This even works at {#link|comptime#}: - {#code_begin|test|packed_structs#} + {#code_begin|test|test_packed_structs#} const std = @import("std"); const native_endian = @import("builtin").target.cpu.arch.endian(); const expect = std.testing.expect; @@ -3316,7 +3316,7 @@ fn doTheTest() !void {Zig allows the address to be taken of a non-byte-aligned field:
- {#code_begin|test|pointer_to_non-byte_aligned_field#} + {#code_begin|test|test_pointer_to_non-byte_aligned_field#} const std = @import("std"); const expect = std.testing.expect; @@ -3341,7 +3341,7 @@ test "pointer to non-byte-aligned field" { However, the pointer to a non-byte-aligned field has special properties and cannot be passed when a normal pointer is expected: - {#code_begin|test_err|expected type#} + {#code_begin|test_err|test_misaligned_pointer|expected type#} const std = @import("std"); const expect = std.testing.expect; @@ -3372,7 +3372,7 @@ fn bar(x: *const u3) u3 {Pointers to non-ABI-aligned fields share the same address as the other fields within their host integer:
- {#code_begin|test|packed_struct_field_addrs#} + {#code_begin|test|test_packed_struct_field_address#} const std = @import("std"); const expect = std.testing.expect; @@ -3422,7 +3422,7 @@ test "pointer to non-bit-aligned field" { Packed structs have the same alignment as their backing integer, however, overaligned pointers to packed structs can override this: - {#code_begin|test|overaligned_packed_struct#} + {#code_begin|test|test_overaligned_packed_struct#} const std = @import("std"); const expect = std.testing.expect; @@ -3501,7 +3501,7 @@ fn List(comptime T: type) type { the struct literal will directly instantiate the {#link|result location|Result Location Semantics#}, with no copy: - {#code_begin|test|struct_result#} + {#code_begin|test|test_struct_result#} const std = @import("std"); const expect = std.testing.expect; @@ -3520,7 +3520,7 @@ test "anonymous struct literal" { The struct type can be inferred. Here the {#link|result location|Result Location Semantics#} does not include a type, and so Zig infers the type: - {#code_begin|test|struct_anon#} + {#code_begin|test|test_anonymous_struct#} const std = @import("std"); const expect = std.testing.expect; @@ -3557,7 +3557,7 @@ fn dump(args: anytype) !void { Like arrays, tuples have a .len field, can be indexed (provided the index is comptime-known) and work with the ++ and ** operators. They can also be iterated over with {#link|inline for#}. - {#code_begin|test|tuple#} + {#code_begin|test|test_tuples#} const std = @import("std"); const expect = std.testing.expect; @@ -3582,7 +3582,7 @@ test "tuple" { {#see_also|comptime|@fieldParentPtr#} {#header_close#} {#header_open|enum#} - {#code_begin|test|enums#} + {#code_begin|test|test_enums#} const expect = @import("std").testing.expect; const mem = @import("std").mem; @@ -3700,7 +3700,7 @@ test "@tagName" {By default, enums are not guaranteed to be compatible with the C ABI:
- {#code_begin|obj_err|parameter of type 'test.Foo' not allowed in function with calling convention 'C'#} + {#code_begin|obj_err|enum_export_error|parameter of type 'enum_export_error.Foo' not allowed in function with calling convention 'C'#} const Foo = enum { a, b, c }; export fn entry(foo: Foo) void { _ = foo; } {#code_end#} @@ -3708,7 +3708,7 @@ export fn entry(foo: Foo) void { _ = foo; } For a C-ABI-compatible enum, provide an explicit tag type to the enum: - {#code_begin|obj#} + {#code_begin|obj|enum_export#} const Foo = enum(c_int) { a, b, c }; export fn entry(foo: Foo) void { _ = foo; } {#code_end#} @@ -3801,7 +3801,7 @@ test "switch on non-exhaustive enum" { {#link|Accessing the non-active field|Wrong Union Field Access#} is safety-checked {#link|Undefined Behavior#}: - {#code_begin|test_err|access of union field 'float' while field 'int' is active#} + {#code_begin|test_err|test_wrong_union_access|access of union field 'float' while field 'int' is active#} const Payload = union { int: i64, float: f64, @@ -3963,7 +3963,7 @@ test "@tagName" { {#header_open|Anonymous Union Literals#}{#link|Anonymous Struct Literals#} syntax can be used to initialize unions without specifying the type:
- {#code_begin|test|anon_union#} + {#code_begin|test|test_anonymous_union#} const std = @import("std"); const expect = std.testing.expect; @@ -3997,7 +3997,7 @@ fn makeNumber() Number { This is typically used for type safety when interacting with C code that does not expose struct details. Example: - {#code_begin|test_err|expected type '*test.Derp', found '*test.Wat'#} + {#code_begin|test_err|test_opaque|expected type '*test_opaque.Derp', found '*test_opaque.Wat'#} const Derp = opaque {}; const Wat = opaque {}; @@ -4016,7 +4016,7 @@ test "call foo" {Blocks are used to limit the scope of variable declarations:
- {#code_begin|test_err|use of undeclared identifier 'x'#} + {#code_begin|test_err|test_blocks|use of undeclared identifier 'x'#} test "access variable after block scope" { { var x: i32 = 1; @@ -4048,7 +4048,7 @@ test "labeled break from labeled block expression" { {#header_open|Shadowing#}{#link|Identifiers#} are never allowed to "hide" other identifiers by using the same name:
- {#code_begin|test_err|local variable shadows declaration#} + {#code_begin|test_err|test_shadowing|local variable shadows declaration#} const pi = 3.14; test "inside test block" { @@ -4079,7 +4079,7 @@ test "separate scopes" { {#header_open|Empty Blocks#}An empty block is equivalent to {#syntax#}void{}{#endsyntax#}:
- {#code_begin|test|empty_block#} + {#code_begin|test|test_empty_block#} const std = @import("std"); const expect = std.testing.expect; @@ -4095,7 +4095,7 @@ test { {#header_close#} {#header_open|switch#} - {#code_begin|test|switch#} + {#code_begin|test|test_switch#} const std = @import("std"); const builtin = @import("builtin"); const expect = std.testing.expect; @@ -4212,7 +4212,7 @@ test "switch on tagged union" { When a {#syntax#}switch{#endsyntax#} expression does not have an {#syntax#}else{#endsyntax#} clause, it must exhaustively list all the possible values. Failure to do so is a compile error: - {#code_begin|test_err|unhandled enumeration value#} + {#code_begin|test_err|test_unhandled_enumeration_value|unhandled enumeration value#} const Color = enum { auto, off, @@ -4390,7 +4390,7 @@ test "test" { A while loop is used to repeatedly execute an expression until some condition is no longer true. - {#code_begin|test|while#} + {#code_begin|test|test_while#} const expect = @import("std").testing.expect; test "while basic" { @@ -4404,7 +4404,7 @@ test "while basic" {Use {#syntax#}break{#endsyntax#} to exit a while loop early.
- {#code_begin|test|while#} + {#code_begin|test|test_while_break#} const expect = @import("std").testing.expect; test "while break" { @@ -4420,7 +4420,7 @@ test "while break" {Use {#syntax#}continue{#endsyntax#} to jump back to the beginning of the loop.
- {#code_begin|test|while#} + {#code_begin|test|test_while_continue#} const expect = @import("std").testing.expect; test "while continue" { @@ -4438,7 +4438,7 @@ test "while continue" { While loops support a continue expression which is executed when the loop is continued. The {#syntax#}continue{#endsyntax#} keyword respects this expression. - {#code_begin|test|while#} + {#code_begin|test|test_while_continue_expression#} const expect = @import("std").testing.expect; test "while loop continue expression" { @@ -4467,7 +4467,7 @@ test "while loop continue expression, more complicated" { When you {#syntax#}break{#endsyntax#} from a while loop, the {#syntax#}else{#endsyntax#} branch is not evaluated. - {#code_begin|test|while#} + {#code_begin|test|test_while_else#} const expect = @import("std").testing.expect; test "while else" { @@ -4487,7 +4487,7 @@ fn rangeHasNumber(begin: usize, end: usize, number: usize) bool { {#header_open|Labeled while#}When a {#syntax#}while{#endsyntax#} loop is labeled, it can be referenced from a {#syntax#}break{#endsyntax#} or {#syntax#}continue{#endsyntax#} from within a nested loop:
- {#code_begin|test|test_nested_break#} + {#code_begin|test|test_while_nested_break#} test "nested break" { outer: while (true) { while (true) { @@ -4520,7 +4520,7 @@ test "nested continue" { The {#syntax#}else{#endsyntax#} branch is allowed on optional iteration. In this case, it will be executed on the first null value encountered. - {#code_begin|test|while#} + {#code_begin|test|test_while_null_capture#} const expect = @import("std").testing.expect; test "while null capture" { @@ -4562,7 +4562,7 @@ fn eventuallyNullSequence() ?u32 { When the {#syntax#}else |x|{#endsyntax#} syntax is present on a {#syntax#}while{#endsyntax#} expression, the while condition must have an {#link|Error Union Type#}. - {#code_begin|test|while#} + {#code_begin|test|test_while_error_capture#} const expect = @import("std").testing.expect; test "while error union capture" { @@ -4627,7 +4627,7 @@ fn typeNameLength(comptime T: type) usize { {#see_also|if|Optionals|Errors|comptime|unreachable#} {#header_close#} {#header_open|for#} - {#code_begin|test|for#} + {#code_begin|test|test_for#} const expect = @import("std").testing.expect; test "for basics" { @@ -4695,7 +4695,7 @@ test "for else" { {#header_open|Labeled for#}When a {#syntax#}for{#endsyntax#} loop is labeled, it can be referenced from a {#syntax#}break{#endsyntax#} or {#syntax#}continue{#endsyntax#} from within a nested loop:
- {#code_begin|test|test_nested_break#} + {#code_begin|test|test_for_nested_break#} const std = @import("std"); const expect = std.testing.expect; @@ -4731,7 +4731,7 @@ test "nested continue" { The capture value and iterator value of inlined for loops are compile-time known. - {#code_begin|test|test_inline_loop#} + {#code_begin|test|test_inline_for#} const expect = @import("std").testing.expect; test "inline for loop" { @@ -4766,7 +4766,7 @@ fn typeNameLength(comptime T: type) usize { {#see_also|while|comptime|Arrays|Slices#} {#header_close#} {#header_open|if#} - {#code_begin|test|if#} + {#code_begin|test|test_if#} // If expressions have three uses, corresponding to the three types: // * bool // * ?T @@ -4927,7 +4927,7 @@ test "if error union with optional" { {#see_also|Optionals|Errors#} {#header_close#} {#header_open|defer#} - {#code_begin|test|defer#} + {#code_begin|test|test_defer#} const std = @import("std"); const expect = std.testing.expect; const print = std.debug.print; @@ -4973,7 +4973,7 @@ test "defer unwinding" { deferUnwindExample(); } {#code_end#} - {#code_begin|test_err|cannot return from defer expression#} + {#code_begin|test_err|test_invalid_defer|cannot return from defer expression#} // Inside a defer expression the return statement is not allowed. fn deferInvalidExample() !void { defer { @@ -4983,7 +4983,7 @@ fn deferInvalidExample() !void { return error.DeferError; } {#code_end#} - {#code_begin|test|errdefer#} + {#code_begin|test|test_errdefer#} const std = @import("std"); const print = std.debug.print; @@ -5052,7 +5052,7 @@ test "basic math" { } {#code_end#}In fact, this is how {#syntax#}std.debug.assert{#endsyntax#} is implemented:
- {#code_begin|test_err#} + {#code_begin|test_err|test_assertion_failure#} // This is how std.debug.assert is implemented fn assert(ok: bool) void { if (!ok) unreachable; // assertion failure @@ -5065,7 +5065,7 @@ test "this will fail" { {#code_end#} {#header_close#} {#header_open|At Compile-Time#} - {#code_begin|test_err|unreachable code#} + {#code_begin|test_err|test_comptime_unreachable|unreachable code#} const assert = @import("std").debug.assert; test "type of unreachable" { @@ -5107,7 +5107,7 @@ test "noreturn" { } {#code_end#}Another use case for {#syntax#}noreturn{#endsyntax#} is the {#syntax#}exit{#endsyntax#} function:
- {#code_begin|test|noreturn_from_exit#} + {#code_begin|test|test_noreturn_from_exit#} {#target_windows#} const std = @import("std"); const builtin = @import("builtin"); @@ -5130,7 +5130,7 @@ fn bar() anyerror!u32 { {#header_close#} {#header_open|Functions#} - {#code_begin|test|functions#} + {#code_begin|test|test_functions#} const std = @import("std"); const builtin = @import("builtin"); const native_arch = builtin.cpu.arch; @@ -5206,7 +5206,7 @@ test "function" { as parameters, Zig may choose to copy and pass by value, or pass by reference, whichever way Zig decides will be faster. This is made possible, in part, by the fact that parameters are immutable. - {#code_begin|test|pass_by_reference_or_value#} + {#code_begin|test|test_pass_by_reference_or_value#} const Point = struct { x: i32, y: i32, @@ -5283,7 +5283,7 @@ test "fn reflection" {You can {#link|coerce|Type Coercion#} an error from a subset to a superset:
- {#code_begin|test|coercing_subset_to_superset#} + {#code_begin|test|test_coerce_error_subset_to_superset#} const std = @import("std"); const FileOpenError = error { @@ -5308,7 +5308,7 @@ fn foo(err: AllocationError) FileOpenError {But you cannot {#link|coerce|Type Coercion#} an error from a superset to a subset:
- {#code_begin|test_err|not a member of destination error set#} + {#code_begin|test_err|test_coerce_error_superset_to_subset|not a member of destination error set#} const FileOpenError = error { AccessDenied, OutOfMemory, @@ -5330,11 +5330,11 @@ fn foo(err: FileOpenError) AllocationError {There is a shortcut for declaring an error set with only 1 value, and then getting that value:
- {#code_begin|syntax#} + {#code_begin|syntax|single_value_error_set_shortcut#} const err = error.FileNotFound; {#code_end#}This is equivalent to:
- {#code_begin|syntax#} + {#code_begin|syntax|single_value_error_set#} const err = (error {FileNotFound}).FileNotFound; {#code_end#}@@ -5431,7 +5431,7 @@ test "parse u64" { {#header_open|catch#}
If you want to provide a default value, you can use the {#syntax#}catch{#endsyntax#} binary operator:
- {#code_begin|syntax#} + {#code_begin|syntax|catch#} const parseU64 = @import("error_union_parsing_u64.zig").parseU64; fn doAThing(str: []u8) void { @@ -5448,7 +5448,7 @@ fn doAThing(str: []u8) void { {#header_open|try#}Let's say you wanted to return the error if you got one, otherwise continue with the function logic:
- {#code_begin|syntax#} + {#code_begin|syntax|catch_err_return#} const parseU64 = @import("error_union_parsing_u64.zig").parseU64; fn doAThing(str: []u8) !void { @@ -5459,7 +5459,7 @@ fn doAThing(str: []u8) !void {There is a shortcut for this. The {#syntax#}try{#endsyntax#} expression:
- {#code_begin|syntax#} + {#code_begin|syntax|try#} const parseU64 = @import("error_union_parsing_u64.zig").parseU64; fn doAThing(str: []u8) !void { @@ -5543,7 +5543,7 @@ fn createFoo(param: i32) !Foo { It should be noted that {#syntax#}errdefer{#endsyntax#} statements only last until the end of the block they are written in, and therefore are not run if an error is returned outside of that block: - {#code_begin|test_err|1 tests leaked memory#} + {#code_begin|test_err|test_errdefer_slip_ups|1 tests leaked memory#} const std = @import("std"); const Allocator = std.mem.Allocator; @@ -5635,7 +5635,7 @@ test "createFoo" { The fact that errdefers only last for the block they are declared in is especially important when using loops: - {#code_begin|test_err|3 errors were logged#} + {#code_begin|test_err|test_errdefer_loop_leak|3 errors were logged#} const std = @import("std"); const Allocator = std.mem.Allocator; @@ -5799,7 +5799,7 @@ test "merge error sets" { Because many functions in Zig return a possible error, Zig supports inferring the error set. To infer the error set for a function, prepend the {#syntax#}!{#endsyntax#} operator to the function’s return type, like {#syntax#}!T{#endsyntax#}: -{#code_begin|test|inferred_error_sets#} + {#code_begin|test|test_inferred_error_sets#} // With an inferred error set pub fn add_inferred(comptime T: type, a: T, b: T) !T { const ov = @addWithOverflow(a, b); @@ -5825,7 +5825,7 @@ test "inferred error set" { error.Overflow => {}, // ok } } -{#code_end#} + {#code_end#}When a function has an inferred error set, that function becomes generic and thus it becomes trickier to do certain things with it, such as obtain a function pointer, or have an error @@ -5845,7 +5845,7 @@ test "inferred error set" {
Error Return Traces show all the points in the code that an error was returned to the calling function. This makes it practical to use {#link|try#} everywhere and then still be able to know what happened if an error ends up bubbling all the way out of your application.
- {#code_begin|exe_err#} + {#code_begin|exe_err|error_return_trace#} pub fn main() !void { try foo(12); } @@ -5894,7 +5894,7 @@ fn bang2() !void { but the original error that started this whole thing was {#syntax#}FileNotFound{#endsyntax#}. In the {#syntax#}bar{#endsyntax#} function, the code handles the original error code, and then returns another one, from the switch statement. Error Return Traces make this clear, whereas a stack trace would look like this: - {#code_begin|exe_err#} + {#code_begin|exe_err|stack_trace#} pub fn main() void { foo(12); } @@ -6016,7 +6016,7 @@ fn __zig_return_error(stack_trace: *StackTrace) void { The question mark symbolizes the optional type. You can convert a type to an optional type by putting a question mark in front of it, like this: - {#code_begin|syntax#} + {#code_begin|syntax|optional_integer#} // normal integer const normal_int: i32 = 1234; @@ -6137,7 +6137,7 @@ test "optional type" { Just like {#link|undefined#}, {#syntax#}null{#endsyntax#} has its own type, and the only way to use it is to cast it to a different type: - {#code_begin|syntax#} + {#code_begin|syntax|null#} const optional_value: ?i32 = null; {#code_end#} {#header_close#} @@ -6176,7 +6176,7 @@ test "optional pointers" {Type coercion occurs when one type is expected, but different type is provided:
- {#code_begin|test|type_coercion#} + {#code_begin|test|test_type_coercion#} test "type coercion - variable declaration" { var a: u8 = 1; var b: u16 = a; @@ -6216,7 +6216,7 @@ test "type coercion - @as builtin" {These casts are no-ops at runtime since the value representation does not change.
- {#code_begin|test|no_op_casts#} + {#code_begin|test|test_no_op_casts#} test "type coercion - const qualification" { var a: i32 = 1; var b: *i32 = &a; @@ -6228,7 +6228,7 @@ fn foo(_: *const i32) void {}In addition, pointers coerce to const optional pointers:
- {#code_begin|test|pointer_coerce_const_optional#} + {#code_begin|test|test_pointer_coerce_const_optional#} const std = @import("std"); const expect = std.testing.expect; const mem = std.mem; @@ -6285,7 +6285,7 @@ test "float widening" {Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example:
- {#code_begin|test_err|ignored#} + {#code_begin|test_err|test_expression_ignored|ignored#} test "ignoring expression value" { foo(); } @@ -6697,7 +6697,7 @@ fn foo() i32 { } {#code_end#}However, if the expression has type {#syntax#}void{#endsyntax#}, there will be no error. Function return values can also be explicitly ignored by assigning them to {#syntax#}_{#endsyntax#}.
- {#code_begin|test|void_ignored#} + {#code_begin|test|test_void_ignored#} test "void is ignored" { returnsVoid(); } @@ -6727,7 +6727,7 @@ fn foo() i32 { declarations of the operand, which must be a {#link|struct#}, {#link|union#}, {#link|enum#}, or {#link|opaque#}, into the namespace: - {#code_begin|test|usingnamespace#} + {#code_begin|test|test_usingnamespace#} test "using std namespace" { const S = struct { usingnamespace @import("std"); @@ -6769,7 +6769,7 @@ pub usingnamespace @cImport({Compile-time parameters is how Zig implements generics. It is compile-time duck typing.
- {#code_begin|syntax#} + {#code_begin|syntax|compile-time_duck_typing#} fn max(comptime T: type, a: T, b: T) T { return if (a > b) a else b; } @@ -6795,7 +6795,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {For example, if we were to introduce another function to the above snippet:
- {#code_begin|test_err|unable to resolve comptime value#} + {#code_begin|test_err|test_unresolved_comptime_value|unable to resolve comptime value#} fn max(comptime T: type, a: T, b: T) T { return if (a > b) a else b; } @@ -6821,7 +6821,7 @@ fn foo(condition: bool) void {For example:
- {#code_begin|test_err|operator > not allowed for type 'bool'#} + {#code_begin|test_err|test_comptime_mismatched_type|operator > not allowed for type 'bool'#} fn max(comptime T: type, a: T, b: T) T { return if (a > b) a else b; } @@ -6834,7 +6834,7 @@ test "try to compare bools" { value is known at compile-time. This means that we actually could make this work for the bool type if we wanted to: - {#code_begin|test|comptime_max_with_bool#} + {#code_begin|test|test_comptime_max_with_bool#} fn max(comptime T: type, a: T, b: T) T { if (T == bool) { return a or b; @@ -6857,7 +6857,7 @@ test "try to compare bools" { This means that the actual function generated for {#syntax#}max{#endsyntax#} in this situation looks like this: - {#code_begin|syntax#} + {#code_begin|syntax|compiler_generated_function#} fn max(a: bool, b: bool) bool { return a or b; } @@ -6884,7 +6884,7 @@ fn max(a: bool, b: bool) bool {For example:
- {#code_begin|test|comptime_vars#} + {#code_begin|test|test_comptime_evaluation#} const expect = @import("std").testing.expect; const CmdFn = struct { @@ -6966,7 +6966,7 @@ fn performFn(start_value: i32) i32 { use a {#syntax#}comptime{#endsyntax#} expression to guarantee that the expression will be evaluated at compile-time. If this cannot be accomplished, the compiler will emit an error. For example: - {#code_begin|test_err|comptime call of extern function#} + {#code_begin|test_err|test_comptime_call_extern_function|comptime call of extern function#} extern fn exit() noreturn; test "foo" { @@ -6997,7 +6997,7 @@ test "foo" {Let's look at an example:
- {#code_begin|test|fibonacci_recursion#} + {#code_begin|test|test_fibonacci_recursion#} const expect = @import("std").testing.expect; fn fibonacci(index: u32) u32 { @@ -7018,7 +7018,7 @@ test "fibonacci" {Imagine if we had forgotten the base case of the recursive function and tried to run the tests:
- {#code_begin|test_err|overflow of integer type#} + {#code_begin|test_err|test_fibonacci_comptime_overflow|overflow of integer type#} const expect = @import("std").testing.expect; fn fibonacci(index: u32) u32 { @@ -7041,7 +7041,7 @@ test "fibonacci" { undefined behavior, which is always a compile error if the compiler knows it happened. But what would have happened if we used a signed integer? - {#code_begin|syntax#} + {#code_begin|syntax|fibonacci_comptime_infinite_recursion#} const assert = @import("std").debug.assert; fn fibonacci(index: i32) i32 { @@ -7073,7 +7073,7 @@ test "fibonacci" { What if we fix the base case, but put the wrong value in the {#syntax#}expect{#endsyntax#} line? - {#code_begin|test_err|reached unreachable#} + {#code_begin|test_err|test_fibonacci_comptime_unreachable|reached unreachable#} const assert = @import("std").debug.assert; fn fibonacci(index: i32) i32 { @@ -7093,7 +7093,7 @@ test "fibonacci" { {#syntax#}comptime{#endsyntax#} expressions. This means that we can use functions to initialize complex static data. For example: - {#code_begin|test|N_primes#} + {#code_begin|test|test_container-level_comptime_expressions#} const first_25_primes = firstNPrimes(25); const sum_of_first_25_primes = sum(&first_25_primes); @@ -7152,7 +7152,7 @@ test "variable values" {Here is an example of a generic {#syntax#}List{#endsyntax#} data structure.
- {#code_begin|syntax#} + {#code_begin|syntax|generic_data_structure#} fn List(comptime T: type) type { return struct { items: []T, @@ -7177,7 +7177,7 @@ var list = List(i32){To explicitly give a type a name, we assign it to a constant.
- {#code_begin|syntax#} + {#code_begin|syntax|anonymous_struct_name#} const Node = struct { next: ?*Node, name: []const u8, @@ -7360,7 +7360,7 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {And now, what happens if we give too many arguments to {#syntax#}print{#endsyntax#}?
- {#code_begin|test_err|unused argument in 'here is a string: '{s}' here is a number: {}#} + {#code_begin|test_err|test_print_too_many_args|unused argument in 'here is a string: '{s}' here is a number: {}#} const print = @import("std").debug.print; const a_number: i32 = 1234; @@ -7381,7 +7381,7 @@ test "print too many arguments" { Zig doesn't care whether the format argument is a string literal, only that it is a compile-time known value that can be coerced to a {#syntax#}[]const u8{#endsyntax#}: - {#code_begin|exe|print#} + {#code_begin|exe|print_comptime-known_format#} const print = @import("std").debug.print; const a_number: i32 = 1234; @@ -7410,7 +7410,7 @@ pub fn main() void { can use inline assembly. Here is an example of implementing Hello, World on x86_64 Linux using inline assembly: - {#code_begin|exe#} + {#code_begin|exe|inline_assembly#} {#target_linux_x86_64#} pub fn main() noreturn { const msg = "hello world\n"; @@ -7572,7 +7572,7 @@ volatile ( verbatim into one long string and assembled together. There are no template substitution rules regarding%
as there are in inline assembly expressions.
- {#code_begin|test|global-asm#}
+ {#code_begin|test|test_global_assembly#}
{#target_linux_x86_64#}
const std = @import("std");
const expect = std.testing.expect;
@@ -7845,7 +7845,7 @@ comptime {
Calls a function, in the same way that invoking an expression with parentheses does:
- {#code_begin|test|call#} + {#code_begin|test|test_call_builtin#} const expect = @import("std").testing.expect; test "noinline function call" { @@ -7979,7 +7979,7 @@ pub const CallModifier = enum { This function performs a strong atomic compare exchange operation. It's the equivalent of this code, except atomic: - {#code_begin|syntax#} + {#code_begin|syntax|not_atomic_cmpxchgStrong#} fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_value: T) ?T { const old_value = ptr.*; if (old_value == expected_value) { @@ -8060,7 +8060,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val This function can be used to do "printf debugging" on compile-time executing code. - {#code_begin|test_err|found compile log statement#} + {#code_begin|test_err|test_compileLog_builtin|found compile log statement#} const print = @import("std").debug.print; const num1 = blk: { @@ -8081,7 +8081,7 @@ test "main" { not encountered by analysis, the program compiles successfully and the generated executable prints: - {#code_begin|test|without_compileLog#} + {#code_begin|test|test_without_compileLog_builtin#} const print = @import("std").debug.print; const num1 = blk: { @@ -8296,7 +8296,7 @@ test "main" { {#syntax#}options.linkage{#endsyntax#} is {#syntax#}Strong{#endsyntax#}, this is equivalent to the {#syntax#}export{#endsyntax#} keyword used on a function: - {#code_begin|obj#} + {#code_begin|obj|export_builtin#} comptime { @export(internalName, .{ .name = "foo", .linkage = .Strong }); } @@ -8304,12 +8304,12 @@ comptime { fn internalName() callconv(.C) void {} {#code_end#}This is equivalent to:
- {#code_begin|obj#} + {#code_begin|obj|export_builtin_equivalent_code#} export fn foo() void {} {#code_end#}Note that even when using {#syntax#}export{#endsyntax#}, the {#syntax#}@"foo"{#endsyntax#} syntax for {#link|identifiers|Identifiers#} can be used to choose any string for the symbol name:
- {#code_begin|obj#} + {#code_begin|obj|export_any_symbol_name#} export fn @"A function name that is a complete sentence."() void {} {#code_end#}@@ -8342,7 +8342,7 @@ export fn @"A function name that is a complete sentence."() void {}
{#syntax#}@field(lhs: anytype, comptime field_name: []const u8) (field){#endsyntax#}
Performs field access by a compile-time string. Works on both fields and declarations.
- {#code_begin|test|field_decl_access_by_string#} + {#code_begin|test|test_field_builtin#} const std = @import("std"); const Point = struct { @@ -8424,7 +8424,7 @@ test "decl access by string" { Returns whether or not a {#link|container|Containers#} has a declaration matching {#syntax#}name{#endsyntax#}. - {#code_begin|test|hasDecl#} + {#code_begin|test|test_hasDecl_builtin#} const std = @import("std"); const expect = std.testing.expect; @@ -8504,7 +8504,7 @@ test "@hasDecl" { Attempting to convert a number which is out of range of the destination type results in safety-protected {#link|Undefined Behavior#}. - {#code_begin|test_err|cast truncated bits#} + {#code_begin|test_err|test_intCast_builtin|cast truncated bits#} test "integer cast panic" { var a: u16 = 0xabcd; var b: u8 = @intCast(u8, a); @@ -8654,7 +8654,7 @@ mem.set(u8, dest, c);{#endsyntax#} designers targeting Wasm. So unless you are writing a new allocator from scratch, you should use something like {#syntax#}@import("std").heap.WasmPageAllocator{#endsyntax#}. - {#code_begin|test|wasmMemoryGrow#} + {#code_begin|test|test_wasmMemoryGrow_builtin#} const std = @import("std"); const native_arch = @import("builtin").target.cpu.arch; const expect = std.testing.expect; @@ -8855,7 +8855,7 @@ pub const PrefetchOptions = struct {Example:
- {#code_begin|test_err|evaluation exceeded 1000 backwards branches#} + {#code_begin|test_err|test_without_setEvalBranchQuota_builtin|evaluation exceeded 1000 backwards branches#} test "foo" { comptime { var i = 0; @@ -8864,7 +8864,7 @@ test "foo" { } {#code_end#}Now we use {#syntax#}@setEvalBranchQuota{#endsyntax#}:
- {#code_begin|test|setEvalBranchQuota#} + {#code_begin|test|test_setEvalBranchQuota_builtin#} test "foo" { comptime { @setEvalBranchQuota(1001); @@ -8882,7 +8882,7 @@ test "foo" {Sets the floating point mode of the current scope. Possible values are:
- {#code_begin|syntax#} + {#code_begin|syntax|FloatMode#} pub const FloatMode = enum { Strict, Optimized, @@ -8917,7 +8917,7 @@ pub const FloatMode = enum {Sets whether runtime safety checks are enabled for the scope that contains the function call.
- {#code_begin|test_safety|integer overflow#} + {#code_begin|test_safety|test_setRuntimeSafety_builtin|integer overflow#} {#code_release_fast#} test "@setRuntimeSafety" { // The builtin applies to the scope that it is called in. So here, integer overflow @@ -9020,7 +9020,7 @@ test "@setRuntimeSafety" { {#link|pointer|Pointers#}, or {#syntax#}bool{#endsyntax#}. The mask may be any vector length, and its length determines the result length. - {#code_begin|test|vector_shuffle#} + {#code_begin|test|test_shuffle_builtin#} const std = @import("std"); const expect = std.testing.expect; @@ -9068,7 +9068,7 @@ test "vector @shuffle" { Produces a vector of length {#syntax#}len{#endsyntax#} where each element is the value {#syntax#}scalar{#endsyntax#}: - {#code_begin|test|vector_splat#} + {#code_begin|test|test_splat_builtin#} const std = @import("std"); const expect = std.testing.expect; @@ -9111,7 +9111,7 @@ test "vector @splat" { types the operation associativity is preserved, unless the float mode is set to {#syntax#}Optimized{#endsyntax#}. - {#code_begin|test|vector_reduce#} + {#code_begin|test|test_reduce_builtin#} const std = @import("std"); const expect = std.testing.expect; @@ -9133,7 +9133,7 @@ test "vector @reduce" {Returns a {#syntax#}SourceLocation{#endsyntax#} struct representing the function's name and location in the source code. This must be called in a function.
- {#code_begin|test|source_location#} + {#code_begin|test|test_src_builtin#} const std = @import("std"); const expect = std.testing.expect; @@ -9147,7 +9147,7 @@ fn doTheTest() !void { try expect(src.line == 9); try expect(src.column == 17); try expect(std.mem.endsWith(u8, src.fn_name, "doTheTest")); - try expect(std.mem.endsWith(u8, src.file, "source_location.zig")); + try expect(std.mem.endsWith(u8, src.file, "test_src_builtin.zig")); } {#code_end#} {#header_close#} @@ -9329,7 +9329,7 @@ fn doTheTest() !void { Returns the innermost struct, enum, or union that this function call is inside. This can be useful for an anonymous struct that needs to refer to itself: - {#code_begin|test|this_innermost#} + {#code_begin|test|test_this_builtin#} const std = @import("std"); const expect = std.testing.expect; @@ -9370,7 +9370,7 @@ fn List(comptime T: type) type {Calling {#syntax#}@truncate{#endsyntax#} on a number out of range of the destination type is well defined and working code:
- {#code_begin|test|truncate#} + {#code_begin|test|test_truncate_builtin#} const std = @import("std"); const expect = std.testing.expect; @@ -9458,7 +9458,7 @@ test "integer truncation" {The expressions are evaluated, however they are guaranteed to have no runtime side-effects:
- {#code_begin|test|no_runtime_side_effects#} + {#code_begin|test|test_TypeOf_builtin#} const std = @import("std"); const expect = std.testing.expect; @@ -9592,14 +9592,14 @@ pub fn build(b: *Builder) void {When a safety check fails, Zig crashes with a stack trace, like this:
- {#code_begin|test_err|reached unreachable code#} + {#code_begin|test_err|test_undefined_behavior|reached unreachable code#} test "safety check" { unreachable; } {#code_end#} {#header_open|Reaching Unreachable Code#}At compile-time:
- {#code_begin|test_err|reached unreachable code#} + {#code_begin|test_err|test_comptime_reaching_unreachable|reached unreachable code#} comptime { assert(false); } @@ -9608,7 +9608,7 @@ fn assert(ok: bool) void { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_reaching_unreachable#} const std = @import("std"); pub fn main() void { @@ -9618,7 +9618,7 @@ pub fn main() void { {#header_close#} {#header_open|Index out of Bounds#}At compile-time:
- {#code_begin|test_err|index 5 outside array of length 5#} + {#code_begin|test_err|test_comptime_index_out_of_bounds|index 5 outside array of length 5#} comptime { const array: [5]u8 = "hello".*; const garbage = array[5]; @@ -9626,7 +9626,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_index_out_of_bounds#} pub fn main() void { var x = foo("hello"); _ = x; @@ -9639,7 +9639,7 @@ fn foo(x: []const u8) u8 { {#header_close#} {#header_open|Cast Negative Number to Unsigned Integer#}At compile-time:
- {#code_begin|test_err|type 'u32' cannot represent integer value '-1'#} + {#code_begin|test_err|test_comptime_invalid_cast|type 'u32' cannot represent integer value '-1'#} comptime { var value: i32 = -1; const unsigned = @intCast(u32, value); @@ -9647,7 +9647,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_invalid_cast#} const std = @import("std"); pub fn main() void { @@ -9662,7 +9662,7 @@ pub fn main() void { {#header_close#} {#header_open|Cast Truncates Data#}At compile-time:
- {#code_begin|test_err|type 'u8' cannot represent integer value '300'#} + {#code_begin|test_err|test_comptime_invalid_cast_truncate|type 'u8' cannot represent integer value '300'#} comptime { const spartan_count: u16 = 300; const byte = @intCast(u8, spartan_count); @@ -9670,7 +9670,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_invalid_cast_truncate#} const std = @import("std"); pub fn main() void { @@ -9697,14 +9697,14 @@ pub fn main() void {Example with addition at compile-time:
- {#code_begin|test_err|overflow of integer type 'u8' with value '256'#} + {#code_begin|test_err|test_comptime_overflow|overflow of integer type 'u8' with value '256'#} comptime { var byte: u8 = 255; byte += 1; } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_overflow#} const std = @import("std"); pub fn main() void { @@ -9726,7 +9726,7 @@ pub fn main() void {Example of catching an overflow for addition:
- {#code_begin|exe_err#} + {#code_begin|exe_err|math_add#} const math = @import("std").math; const print = @import("std").debug.print; pub fn main() !void { @@ -9755,7 +9755,7 @@ pub fn main() !void {Example of {#link|@addWithOverflow#}:
- {#code_begin|exe#} + {#code_begin|exe|addWithOverflow_builtin#} const print = @import("std").debug.print; pub fn main() void { var byte: u8 = 255; @@ -9779,7 +9779,7 @@ pub fn main() void {At compile-time:
- {#code_begin|test_err|operation caused overflow#} + {#code_begin|test_err|test_comptime_shlExact_overwlow|operation caused overflow#} comptime { const x = @shlExact(@as(u8, 0b01010101), 2); _ = x; } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_shlExact_overflow#} const std = @import("std"); pub fn main() void { @@ -9816,14 +9816,14 @@ pub fn main() void { {#header_close#} {#header_open|Exact Right Shift Overflow#}At compile-time:
- {#code_begin|test_err|exact shift shifted out 1 bits#} + {#code_begin|test_err|test_comptime_shrExact_overflow|exact shift shifted out 1 bits#} comptime { const x = @shrExact(@as(u8, 0b10101010), 2); _ = x; } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_shrExact_overflow#} const std = @import("std"); pub fn main() void { @@ -9835,7 +9835,7 @@ pub fn main() void { {#header_close#} {#header_open|Division by Zero#}At compile-time:
- {#code_begin|test_err|division by zero#} + {#code_begin|test_err|test_comptime_division_by_zero|division by zero#} comptime { const a: i32 = 1; const b: i32 = 0; @@ -9844,7 +9844,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_division_by_zero#} const std = @import("std"); pub fn main() void { @@ -9857,7 +9857,7 @@ pub fn main() void { {#header_close#} {#header_open|Remainder Division by Zero#}At compile-time:
- {#code_begin|test_err|division by zero#} + {#code_begin|test_err|test_comptime_remainder_division_by_zero|division by zero#} comptime { const a: i32 = 10; const b: i32 = 0; @@ -9866,7 +9866,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_remainder_division_by_zero#} const std = @import("std"); pub fn main() void { @@ -9879,7 +9879,7 @@ pub fn main() void { {#header_close#} {#header_open|Exact Division Remainder#}At compile-time:
- {#code_begin|test_err|exact division produced remainder#} + {#code_begin|test_err|test_comptime_divExact_remainder|exact division produced remainder#} comptime { const a: u32 = 10; const b: u32 = 3; @@ -9888,7 +9888,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_divExact_remainder#} const std = @import("std"); pub fn main() void { @@ -9901,7 +9901,7 @@ pub fn main() void { {#header_close#} {#header_open|Attempt to Unwrap Null#}At compile-time:
- {#code_begin|test_err|unable to unwrap null#} + {#code_begin|test_err|test_comptime_unwrap_null|unable to unwrap null#} comptime { const optional_number: ?i32 = null; const number = optional_number.?; @@ -9909,7 +9909,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_unwrap_null#} const std = @import("std"); pub fn main() void { @@ -9920,7 +9920,7 @@ pub fn main() void { {#code_end#}One way to avoid this crash is to test for null instead of assuming non-null, with the {#syntax#}if{#endsyntax#} expression:
- {#code_begin|exe|test#} + {#code_begin|exe|testing_null_with_if#} const print = @import("std").debug.print; pub fn main() void { const optional_number: ?i32 = null; @@ -9936,7 +9936,7 @@ pub fn main() void { {#header_close#} {#header_open|Attempt to Unwrap Error#}At compile-time:
- {#code_begin|test_err|caught unexpected error 'UnableToReturnNumber'#} + {#code_begin|test_err|test_comptime_unwrap_error|caught unexpected error 'UnableToReturnNumber'#} comptime { const number = getNumberOrFail() catch unreachable; _ = number; @@ -9947,7 +9947,7 @@ fn getNumberOrFail() !i32 { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_unwrap_error#} const std = @import("std"); pub fn main() void { @@ -9961,7 +9961,7 @@ fn getNumberOrFail() !i32 { {#code_end#}One way to avoid this crash is to test for an error instead of assuming a successful result, with the {#syntax#}if{#endsyntax#} expression:
- {#code_begin|exe#} + {#code_begin|exe|testing_error_with_if#} const print = @import("std").debug.print; pub fn main() void { @@ -9982,7 +9982,7 @@ fn getNumberOrFail() !i32 { {#header_close#} {#header_open|Invalid Error Code#}At compile-time:
- {#code_begin|test_err|integer value '11' represents no error#} + {#code_begin|test_err|test_comptime_invalid_error_code|integer value '11' represents no error#} comptime { const err = error.AnError; const number = @errorToInt(err) + 10; @@ -9991,7 +9991,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_invalid_error_code#} const std = @import("std"); pub fn main() void { @@ -10004,7 +10004,7 @@ pub fn main() void { {#header_close#} {#header_open|Invalid Enum Cast#}At compile-time:
- {#code_begin|test_err|enum 'test.Foo' has no tag with value '3'#} + {#code_begin|test_err|test_comptime_invalid_enum_cast|enum 'test_comptime_invalid_enum_cast.Foo' has no tag with value '3'#} const Foo = enum { a, b, @@ -10017,7 +10017,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_invalid_enum_cast#} const std = @import("std"); const Foo = enum { @@ -10036,7 +10036,7 @@ pub fn main() void { {#header_open|Invalid Error Set Cast#}At compile-time:
- {#code_begin|test_err|'error.B' not a member of error set 'error{A,C}'#} + {#code_begin|test_err|test_comptime_invalid_error_set_cast|'error.B' not a member of error set 'error{A,C}'#} const Set1 = error{ A, B, @@ -10050,7 +10050,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_invalid_error_set_cast#} const std = @import("std"); const Set1 = error{ @@ -10073,7 +10073,7 @@ fn foo(set1: Set1) void { {#header_open|Incorrect Pointer Alignment#}At compile-time:
- {#code_begin|test_err|pointer address 0x1 is not aligned to 4 bytes#} + {#code_begin|test_err|test_comptime_incorrect_pointer_alignment|pointer address 0x1 is not aligned to 4 bytes#} comptime { const ptr = @intToPtr(*align(1) i32, 0x1); const aligned = @alignCast(4, ptr); @@ -10081,7 +10081,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_incorrect_pointer_alignment#} const mem = @import("std").mem; pub fn main() !void { var array align(4) = [_]u32{ 0x11111111, 0x11111111 }; @@ -10097,7 +10097,7 @@ fn foo(bytes: []u8) u32 { {#header_close#} {#header_open|Wrong Union Field Access#}At compile-time:
- {#code_begin|test_err|access of union field 'float' while field 'int' is active#} + {#code_begin|test_err|test_comptime_wrong_union_field_access|access of union field 'float' while field 'int' is active#} comptime { var f = Foo{ .int = 42 }; f.float = 12.34; @@ -10109,7 +10109,7 @@ const Foo = union { }; {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_wrong_union_field_access#} const std = @import("std"); const Foo = union { @@ -10133,7 +10133,7 @@ fn bar(f: *Foo) void {To change the active field of a union, assign the entire union, like this:
- {#code_begin|exe#} + {#code_begin|exe|change_active_union_field#} const std = @import("std"); const Foo = union { @@ -10155,7 +10155,7 @@ fn bar(f: *Foo) void { To change the active field of a union when a meaningful value for the field is not known, use {#link|undefined#}, like this: - {#code_begin|exe#} + {#code_begin|exe|undefined_active_union_field#} const std = @import("std"); const Foo = union { @@ -10188,7 +10188,7 @@ fn bar(f: *Foo) void { allow address zero, but normal {#link|Pointers#} do not.At compile-time:
- {#code_begin|test_err|null pointer casted to type#} + {#code_begin|test_err|test_comptime_invalid_null_pointer_cast|null pointer casted to type#} comptime { const opt_ptr: ?*i32 = null; const ptr = @ptrCast(*i32, opt_ptr); @@ -10196,7 +10196,7 @@ comptime { } {#code_end#}At runtime:
- {#code_begin|exe_err#} + {#code_begin|exe_err|runtime_invalid_null_pointer_cast#} pub fn main() void { var opt_ptr: ?*i32 = null; var ptr = @ptrCast(*i32, opt_ptr); @@ -10224,7 +10224,7 @@ pub fn main() void { {#syntax#}std.ArrayList{#endsyntax#} accept an {#syntax#}Allocator{#endsyntax#} parameter in their initialization functions: - {#code_begin|test|allocator#} + {#code_begin|test|test_allocator#} const std = @import("std"); const Allocator = std.mem.Allocator; const expect = std.testing.expect; @@ -10278,7 +10278,7 @@ fn concat(allocator: Allocator, a: []const u8, b: []const u8) ![]u8 { cyclical pattern (such as a video game main loop, or a web server request handler), such that it would make sense to free everything at once at the end? In this case, it is recommended to follow this pattern: - {#code_begin|exe|cli_allocation#} + {#code_begin|exe|cli_allocation#} const std = @import("std"); pub fn main() !void { @@ -10290,7 +10290,7 @@ pub fn main() !void { const ptr = try allocator.create(i32); std.debug.print("ptr={*}\n", .{ptr}); } - {#code_end#} + {#code_end#} When using this kind of allocator, there is no need to free anything manually. Everything gets freed at once with the call to {#syntax#}arena.deinit(){#endsyntax#}. @@ -10328,7 +10328,7 @@ pub fn main() !void {String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section. This is why it is an error to pass a string literal to a mutable slice, like this:
- {#code_begin|test_err|expected type '[]u8', found '*const [5:0]u8'#} + {#code_begin|test_err|test_string_literal_to_slice|expected type '[]u8', found '*const [5:0]u8'#} fn foo(s: []u8) void { _ = s; } @@ -10338,7 +10338,7 @@ test "string literal to mutable slice" { } {#code_end#}However if you make the slice constant, then it works:
- {#code_begin|test|strlit#} + {#code_begin|test|test_string_literal_to_const_slice#} fn foo(s: []const u8) void { _ = s; } @@ -10474,7 +10474,7 @@ test "string literal to constant slice" { which the compiler makes available to every Zig source file. It contains compile-time constants such as the current target, endianness, and release mode. - {#code_begin|syntax#} + {#code_begin|syntax|compile_variables#} const builtin = @import("builtin"); const separator = if (builtin.os.tag == .windows) '\\' else '/'; {#code_end#} @@ -10526,7 +10526,7 @@ const separator = if (builtin.os.tag == .windows) '\\' else '/'; {#header_open|Building an Executable#}This build.zig
file is automatically generated
by zig init-exe.
This build.zig
file is automatically generated
by zig init-lib.
.h
files:
- {#code_begin|exe#}
+ {#code_begin|exe|cImport_builtin#}
{#link_libc#}
const c = @cImport({
// See https://github.com/ziglang/zig/issues/515
@@ -10738,7 +10738,7 @@ pub extern fn do_something(foo: enum_FOO) c_int;{#end_shell_samp#}
To see where the cached files are stored when compiling code that uses {#syntax#}@cImport{#endsyntax#},
use the --verbose-cimport flag:
- {#code_begin|exe|verbose#}
+ {#code_begin|exe|verbose_cimport_flag#}
{#link_libc#}
{#code_verbose_cimport#}
const c = @cImport({
@@ -10856,7 +10856,7 @@ pub const MAKELOCAL = @compileError("unable to translate C expr: unexpected toke
{#header_open|C Variadic Functions#}
Zig supports extern variadic functions.
- {#code_begin|test|variadic_function#} + {#code_begin|test|test_variadic_function#} {#link_libc#} {#code_verbose_cimport#} const std = @import("std"); @@ -10872,7 +10872,7 @@ test "variadic function" {Variadic functions can be implemented using {#link|@cVaStart#}, {#link|@cVaEnd#}, {#link|@cVaArg#} and {#link|@cVaCopy#}
- {#code_begin|test|defining_variadic_function#} + {#code_begin|test|test_defining_variadic_function#} const std = @import("std"); const testing = std.testing; const builtin = @import("builtin"); @@ -10926,7 +10926,7 @@ int main(int argc, char **argv) { return 0; } {#end_syntax_block#} - {#code_begin|syntax|build#} + {#code_begin|syntax|build_c#} const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { @@ -10988,7 +10988,7 @@ int main(int argc, char **argv) { return 0; } {#end_syntax_block#} - {#code_begin|syntax|build#} + {#code_begin|syntax|build_object#} const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { @@ -11040,7 +11040,7 @@ The result is 3{#end_shell_samp#} {#header_open|WASI#}Zig's support for WebAssembly System Interface (WASI) is under active development. Example of using the standard library and reading command line arguments:
- {#code_begin|exe|args#} + {#code_begin|exe|wasi_args#} {#target_wasi#} const std = @import("std"); @@ -11061,7 +11061,7 @@ pub fn main() !void { 2: hello{#end_shell_samp#}A more interesting example would be extracting the list of preopens from the runtime. This is now supported in the standard library via {#syntax#}std.fs.wasi.PreopenList{#endsyntax#}:
- {#code_begin|exe|preopens#} + {#code_begin|exe|wasi_preopens#} {#target_wasi#} const std = @import("std"); const fs = std.fs;