From 76239f2089bfb03b24dac0dcad21c9c430ad076d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
- Note that we also left off the %
from the return type.
- In Zig, if your main function cannot fail, you may use the void
return type.
+ Note that we also left off the !
from the return type.
+ In Zig, if your main function cannot fail, you must use the void
return type.
err
is the error
and is in scope of the expression b
.
-
@@ -1279,7 +1276,8 @@ const ptr = &x;
{#header_close#}
{#header_open|Precedence#}
const value: %u32 = null;
+
const value: error!u32 = error.Broken;
const unwrapped = value catch 1234;
unwrapped == 1234
x() x[] x.y
-!x -x -%x ~x *x &x ?x %x ??x
+a!b
+!x -x -%x ~x *x &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.
- Among the top level declarations available is the error value declaration: + TODO rewrite the errors section to take into account error sets
- {#code_begin|syntax#} -error FileNotFound; -error OutOfMemory; -error UnexpectedToken; - {#code_end#}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;
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.
- 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.
{#code_begin|syntax#}const pure_error = error.FileNotFound;{#code_end#}
- 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 %
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 !
binary operator.
Here is a function to parse a string into a 64-bit integer:
{#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#}
- Notice the return type is %u64
. This means that the function
- either returns an unsigned 64 bit integer, or an error.
+ Notice the return type is !u64
. 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 !
, so the error set is inferred.
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 u64
.
- Both types implicitly cast to %u64
.
+ an error, and at the bottom a return statement that returns a u64
.
+ Both types implicitly cast to error!u64
.
What it looks like to use this function varies depending on what you're @@ -2900,7 +2888,7 @@ fn doAThing(str: []u8) void {
Let's say you wanted to return the error if you got one, otherwise continue with the function logic:
{#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. Thetry
expression:
{#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:
{#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:
{#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:
{#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 {
{#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#}
At compile-time:
- {#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#}At compile-time:
{#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 index 20b905b59b..def6430961 100644 --- 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); \\}