error sets - update langref. all tests passing

master
Andrew Kelley 2018-02-08 03:02:41 -05:00
parent 0d5ff6f462
commit 76239f2089
2 changed files with 49 additions and 82 deletions

View File

@ -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");

View File

@ -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);
\\}