zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 76239f2089bfb03b24dac0dcad21c9c430ad076d (tree)
parent 0d5ff6f4622a492dddbb1fc2b19b3157237500b1
Author: Andrew Kelley <superjoe30@gmail.com>
Date:   Thu,  8 Feb 2018 03:02:41 -0500

error sets - update langref. all tests passing

Diffstat:
Mdoc/langref.html.in | 103+++++++++++++++++++++++++++++++++----------------------------------------------
Mtest/runtime_safety.zig | 28++++++----------------------
2 files changed, 49 insertions(+), 82 deletions(-)

diff --git a/doc/langref.html.in b/doc/langref.html.in @@ -108,7 +108,7 @@ {#code_begin|exe|hello#} const std = @import("std"); -pub fn main() %void { +pub fn main() !void { // If this program is run without stdout attached, exit with an error. var stdout_file = try std.io.getStdOut(); // If this program encounters pipe failure when printing to stdout, exit @@ -129,8 +129,8 @@ pub fn main() void { } {#code_end#} <p> - Note that we also left off the <code class="zig">%</code> from the return type. - In Zig, if your main function cannot fail, you may use the <code class="zig">void</code> return type. + Note that we also left off the <code class="zig">!</code> from the return type. + In Zig, if your main function cannot fail, you must use the <code class="zig">void</code> return type. </p> {#see_also|Values|@import|Errors|Root Source File#} {#header_close#} @@ -151,10 +151,7 @@ const warn = std.debug.warn; const os = std.os; const assert = std.debug.assert; -// error declaration, makes `error.ArgNotFound` available -error ArgNotFound; - -pub fn main() %void { +pub fn main() void { // integers const one_plus_one: i32 = 1 + 1; warn("1 + 1 = {}\n", one_plus_one); @@ -183,7 +180,7 @@ pub fn main() %void { @typeName(@typeOf(nullable_value)), nullable_value); // error union - var number_or_error: %i32 = error.ArgNotFound; + var number_or_error: error!i32 = error.ArgNotFound; warn("\nerror union 1\ntype: {}\nvalue: {}\n", @typeName(@typeOf(number_or_error)), number_or_error); @@ -691,7 +688,7 @@ const warn = @import("std").debug.warn; extern fn foo_strict(x: f64) f64; extern fn foo_optimized(x: f64) f64; -pub fn main() %void { +pub fn main() void { const x = 0.001; warn("optimized = {}\n", foo_optimized(x)); warn("strict = {}\n", foo_strict(x)); @@ -1046,7 +1043,7 @@ a catch |err| b</code></pre></td> <code>err</code> is the <code>error</code> and is in scope of the expression <code>b</code>. </td> <td> - <pre><code class="zig">const value: %u32 = null; + <pre><code class="zig">const value: error!u32 = error.Broken; const unwrapped = value catch 1234; unwrapped == 1234</code></pre> </td> @@ -1279,7 +1276,8 @@ const ptr = &amp;x; {#header_close#} {#header_open|Precedence#} <pre><code>x() x[] x.y -!x -x -%x ~x *x &amp;x ?x %x ??x +a!b +!x -x -%x ~x *x &amp;x ?x ??x x{} ! * / % ** *% + - ++ +% -% @@ -2278,8 +2276,8 @@ fn eventuallyNullSequence() ?u32 { break :blk numbers_left; }; } -error ReachedZero; -fn eventuallyErrorSequence() %u32 { + +fn eventuallyErrorSequence() error!u32 { return if (numbers_left == 0) error.ReachedZero else blk: { numbers_left -= 1; break :blk numbers_left; @@ -2408,7 +2406,7 @@ fn typeNameLength(comptime T: type) usize { // If expressions have three uses, corresponding to the three types: // * bool // * ?T -// * %T +// * error!T const assert = @import("std").debug.assert; @@ -2469,20 +2467,18 @@ test "if nullable" { } } -error BadValue; -error LessBadValue; test "if error union" { // If expressions test for errors. // Note the |err| capture on the else. - const a: %u32 = 0; + const a: error!u32 = 0; if (a) |value| { assert(value == 0); } else |err| { unreachable; } - const b: %u32 = error.BadValue; + const b: error!u32 = error.BadValue; if (b) |value| { unreachable; } else |err| { @@ -2500,7 +2496,7 @@ test "if error union" { } // Access the value by reference using a pointer capture. - var c: %u32 = 3; + var c: error!u32 = 3; if (c) |*value| { *value = 9; } else |err| { @@ -2568,8 +2564,7 @@ test "defer unwinding" { // // This is especially useful in allowing a function to clean up properly // on error, and replaces goto error handling tactics as seen in c. -error DeferError; -fn deferErrorExample(is_error: bool) %void { +fn deferErrorExample(is_error: bool) !void { warn("\nstart of function\n"); // This will always be executed on exit @@ -2678,7 +2673,7 @@ test "foo" { assert(value == 1234); } -fn bar() %u32 { +fn bar() error!u32 { return 1234; } @@ -2791,13 +2786,8 @@ test "implicitly cast to const pointer" { One of the distinguishing features of Zig is its exception handling strategy. </p> <p> - Among the top level declarations available is the error value declaration: + TODO rewrite the errors section to take into account error sets </p> - {#code_begin|syntax#} -error FileNotFound; -error OutOfMemory; -error UnexpectedToken; - {#code_end#} <p> These error values are assigned an unsigned integer value greater than 0 at compile time. You are allowed to declare the same error value more than once, @@ -2809,26 +2799,23 @@ error UnexpectedToken; </p> <p> Each error value across the entire compilation unit gets a unique integer, - and this determines the size of the pure error type. + and this determines the size of the error set type. </p> <p> - The pure error type is one of the error values, and in the same way that pointers - cannot be null, a pure error is always an error. + The error set type is one of the error values, and in the same way that pointers + cannot be null, a error set instance is always an error. </p> {#code_begin|syntax#}const pure_error = error.FileNotFound;{#code_end#} <p> - Most of the time you will not find yourself using a pure error type. Instead, - likely you will be using the error union type. This is when you take a normal type, - and prefix it with the <code>%</code> operator. + Most of the time you will not find yourself using an error set type. Instead, + likely you will be using the error union type. This is when you take an error set + and a normal type, and create an error union with the <code>!</code> binary operator. </p> <p> Here is a function to parse a string into a 64-bit integer: </p> {#code_begin|test#} -error InvalidChar; -error Overflow; - -pub fn parseU64(buf: []const u8, radix: u8) %u64 { +pub fn parseU64(buf: []const u8, radix: u8) !u64 { var x: u64 = 0; for (buf) |c| { @@ -2867,13 +2854,14 @@ test "parse u64" { } {#code_end#} <p> - Notice the return type is <code>%u64</code>. This means that the function - either returns an unsigned 64 bit integer, or an error. + Notice the return type is <code>!u64</code>. This means that the function + either returns an unsigned 64 bit integer, or an error. We left off the error set + to the left of the <code>!</code>, so the error set is inferred. </p> <p> Within the function definition, you can see some return statements that return - a pure error, and at the bottom a return statement that returns a <code>u64</code>. - Both types implicitly cast to <code>%u64</code>. + an error, and at the bottom a return statement that returns a <code>u64</code>. + Both types implicitly cast to <code>error!u64</code>. </p> <p> What it looks like to use this function varies depending on what you're @@ -2900,7 +2888,7 @@ fn doAThing(str: []u8) void { <p>Let's say you wanted to return the error if you got one, otherwise continue with the function logic:</p> {#code_begin|syntax#} -fn doAThing(str: []u8) %void { +fn doAThing(str: []u8) !void { const number = parseU64(str, 10) catch |err| return err; // ... } @@ -2909,7 +2897,7 @@ fn doAThing(str: []u8) %void { There is a shortcut for this. The <code>try</code> expression: </p> {#code_begin|syntax#} -fn doAThing(str: []u8) %void { +fn doAThing(str: []u8) !void { const number = try parseU64(str, 10); // ... } @@ -2959,7 +2947,7 @@ fn doAThing(str: []u8) void { Example: </p> {#code_begin|syntax#} -fn createFoo(param: i32) %Foo { +fn createFoo(param: i32) !Foo { const foo = try tryToAllocateFoo(); // now we have allocated foo. we need to free it if the function fails. // but we want to return it if the function succeeds. @@ -3567,7 +3555,7 @@ pub fn main() void { {#code_begin|syntax#} /// Calls print and then flushes the buffer. -pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) %void { +pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) error!void { const State = enum { Start, OpenBrace, @@ -3639,7 +3627,7 @@ pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) %void { and emits a function that actually looks like this: </p> {#code_begin|syntax#} -pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) %void { +pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) !void { try self.write("here is a string: '"); try self.printValue(arg0); try self.write("' here is a number: "); @@ -3653,7 +3641,7 @@ pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) %void { on the type: </p> {#code_begin|syntax#} -pub fn printValue(self: &OutStream, value: var) %void { +pub fn printValue(self: &OutStream, value: var) !void { const T = @typeOf(value); if (@isInteger(T)) { return self.printInt(T, value); @@ -4582,7 +4570,7 @@ pub const TypeId = enum { {#code_begin|syntax#} const Builder = @import("std").build.Builder; -pub fn build(b: &Builder) %void { +pub fn build(b: &Builder) void { const exe = b.addExecutable("example", "example.zig"); exe.setBuildMode(b.standardReleaseOptions()); b.default_step.dependOn(&exe.step); @@ -4724,7 +4712,7 @@ comptime { {#code_begin|exe_err#} const math = @import("std").math; const warn = @import("std").debug.warn; -pub fn main() %void { +pub fn main() !void { var byte: u8 = 255; byte = if (math.add(u8, byte, 1)) |result| result else |err| { @@ -4752,7 +4740,7 @@ pub fn main() %void { </p> {#code_begin|exe#} const warn = @import("std").debug.warn; -pub fn main() %void { +pub fn main() void { var byte: u8 = 255; var result: u8 = undefined; @@ -4861,14 +4849,12 @@ pub fn main() void { {#header_close#} {#header_open|Attempt to Unwrap Error#} <p>At compile-time:</p> - {#code_begin|test_err|unable to unwrap error 'UnableToReturnNumber'#} + {#code_begin|test_err|caught unexpected error 'UnableToReturnNumber'#} comptime { const number = getNumberOrFail() catch unreachable; } -error UnableToReturnNumber; - -fn getNumberOrFail() %i32 { +fn getNumberOrFail() !i32 { return error.UnableToReturnNumber; } {#code_end#} @@ -4888,9 +4874,7 @@ pub fn main() void { } } -error UnableToReturnNumber; - -fn getNumberOrFail() %i32 { +fn getNumberOrFail() !i32 { return error.UnableToReturnNumber; } {#code_end#} @@ -4898,7 +4882,6 @@ fn getNumberOrFail() %i32 { {#header_open|Invalid Error Code#} <p>At compile-time:</p> {#code_begin|test_err|integer value 11 represents no error#} -error AnError; comptime { const err = error.AnError; const number = u32(err) + 10; @@ -5298,7 +5281,7 @@ int main(int argc, char **argv) { {#code_begin|syntax#} const Builder = @import("std").build.Builder; -pub fn build(b: &Builder) %void { +pub fn build(b: &Builder) void { const obj = b.addObject("base64", "base64.zig"); const exe = b.addCExecutable("test"); diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig @@ -5,7 +5,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\pub fn main() !void { + \\pub fn main() void { \\ @panic("oh no"); \\} ); @@ -14,7 +14,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\pub fn main() !void { + \\pub fn main() void { \\ const a = []i32{1, 2, 3, 4}; \\ baz(bar(a)); \\} @@ -28,7 +28,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = add(65530, 10); \\ if (x == 0) return error.Whatever; @@ -42,7 +41,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = sub(10, 20); \\ if (x == 0) return error.Whatever; @@ -56,7 +54,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = mul(300, 6000); \\ if (x == 0) return error.Whatever; @@ -70,7 +67,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = neg(-32768); \\ if (x == 32767) return error.Whatever; @@ -84,7 +80,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = div(-32768, -1); \\ if (x == 32767) return error.Whatever; @@ -98,7 +93,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = shl(-16385, 1); \\ if (x == 0) return error.Whatever; @@ -112,7 +106,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = shl(0b0010111111111111, 3); \\ if (x == 0) return error.Whatever; @@ -126,7 +119,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = shr(-16385, 1); \\ if (x == 0) return error.Whatever; @@ -140,7 +132,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = shr(0b0010111111111111, 3); \\ if (x == 0) return error.Whatever; @@ -154,8 +145,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; - \\pub fn main() !void { + \\pub fn main() void { \\ const x = div0(999, 0); \\} \\fn div0(a: i32, b: i32) i32 { @@ -167,7 +157,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = divExact(10, 3); \\ if (x == 0) return error.Whatever; @@ -181,7 +170,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = widenSlice([]u8{1, 2, 3, 4, 5}); \\ if (x.len == 0) return error.Whatever; @@ -195,7 +183,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = shorten_cast(200); \\ if (x == 0) return error.Whatever; @@ -209,7 +196,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Whatever; \\pub fn main() !void { \\ const x = unsigned_cast(-10); \\ if (x == 0) return error.Whatever; @@ -226,8 +212,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\ } \\ @import("std").os.exit(0); // test failed \\} - \\error Whatever; - \\pub fn main() !void { + \\pub fn main() void { \\ bar() catch unreachable; \\} \\fn bar() !void { @@ -239,7 +224,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\pub fn main() !void { + \\pub fn main() void { \\ _ = bar(9999); \\} \\fn bar(x: u32) error { @@ -251,7 +236,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} - \\error Wrong; \\pub fn main() !void { \\ var array align(4) = []u32{0x11111111, 0x11111111}; \\ const bytes = ([]u8)(array[0..]); @@ -274,7 +258,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\ int: u32, \\}; \\ - \\pub fn main() !void { + \\pub fn main() void { \\ var f = Foo { .int = 42 }; \\ bar(&f); \\}