docs: finish initial documentation for implicit casts

closes #1514
This commit is contained in:
Andrew Kelley 2019-03-11 19:34:58 -04:00
parent 9b99356551
commit 1a94dec50e
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9

View File

@ -4352,42 +4352,191 @@ test "float widening" {
}
{#code_end#}
{#header_close#}
{#header_open|Implicit Cast: Arrays#}
<p>TODO: [N]T to []const T</p>
<p>TODO: *const [N]T to []const T</p>
<p>TODO: [N]T to *const []const T</p>
<p>TODO: [N]T to ?[]const T</p>
<p>TODO: *[N]T to []T</p>
<p>TODO: *[N]T to [*]T</p>
<p>TODO: *[N]T to ?[*]T</p>
<p>TODO: *T to *[1]T</p>
<p>TODO: [N]T to E![]const T</p>
{#header_open|Implicit Cast: Arrays and Pointers#}
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
// This cast exists primarily so that string literals can be
// passed to functions that accept const slices. However
// it is probably going to be removed from the language when
// https://github.com/ziglang/zig/issues/265 is implemented.
test "[N]T to []const T" {
var x1: []const u8 = "hello";
var x2: []const u8 = [5]u8{ 'h', 'e', 'l', 'l', 111 };
assert(std.mem.eql(u8, x1, x2));
var y: []const f32 = [2]f32{ 1.2, 3.4 };
assert(y[0] == 1.2);
}
// Likewise, it works when the destination type is an error union.
test "[N]T to E![]const T" {
var x1: anyerror![]const u8 = "hello";
var x2: anyerror![]const u8 = [5]u8{ 'h', 'e', 'l', 'l', 111 };
assert(std.mem.eql(u8, try x1, try x2));
var y: anyerror![]const f32 = [2]f32{ 1.2, 3.4 };
assert((try y)[0] == 1.2);
}
// Likewise, it works when the destination type is an optional.
test "[N]T to ?[]const T" {
var x1: ?[]const u8 = "hello";
var x2: ?[]const u8 = [5]u8{ 'h', 'e', 'l', 'l', 111 };
assert(std.mem.eql(u8, x1.?, x2.?));
var y: ?[]const f32 = [2]f32{ 1.2, 3.4 };
assert(y.?[0] == 1.2);
}
// In this cast, the array length becomes the slice length.
test "*[N]T to []T" {
var buf: [5]u8 = "hello";
const x: []u8 = &buf;
assert(std.mem.eql(u8, x, "hello"));
const buf2 = [2]f32{ 1.2, 3.4 };
const x2: []const f32 = &buf2;
assert(std.mem.eql(f32, x2, [2]f32{ 1.2, 3.4 }));
}
// Single-item pointers to arrays can be implicitly casted to
// unknown length pointers.
test "*[N]T to [*]T" {
var buf: [5]u8 = "hello";
const x: [*]u8 = &buf;
assert(x[4] == 'o');
// x[5] would be an uncaught out of bounds pointer dereference!
}
// Likewise, it works when the destination type is an optional.
test "*[N]T to ?[*]T" {
var buf: [5]u8 = "hello";
const x: ?[*]u8 = &buf;
assert(x.?[4] == 'o');
}
// Single-item pointers can be cast to len-1 single-item arrays.
test "*T to *[1]T" {
var x: i32 = 1234;
const y: *[1]i32 = &x;
const z: [*]i32 = y;
assert(z[0] == 1234);
}
{#code_end#}
{#see_also|C Pointers#}
{#header_close#}
{#header_open|Implicit Cast: Optionals#}
<p>TODO: T to ?T</p>
<p>TODO: T to E!?T</p>
<p>TODO: null to ?T</p>
<p>
The payload type of {#link|Optionals#}, as well as {#link|null#}, implicitly cast to the optional type.
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
test "implicit casting to optionals" {
const x: ?i32 = 1234;
const y: ?i32 = null;
assert(x.? == 1234);
assert(y == null);
}
{#code_end#}
<p>It works nested inside the {#link|Error Union Type#}, too:</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
test "implicit casting to optionals wrapped in error union" {
const x: anyerror!?i32 = 1234;
const y: anyerror!?i32 = null;
assert((try x).? == 1234);
assert((try y) == null);
}
{#code_end#}
{#header_close#}
{#header_open|Implicit Cast: T to E!T#}
<p>TODO</p>
{#header_open|Implicit Cast: Error Unions#}
<p>The the payload type of an {#link|Error Union Type#} as well as the {#link|Error Set Type#}
implicitly cast to the error union type:
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
test "implicit casting to error unions" {
const x: anyerror!i32 = 1234;
const y: anyerror!i32 = error.Failure;
assert((try x) == 1234);
std.testing.expectError(error.Failure, y);
}
{#code_end#}
{#header_close#}
{#header_open|Implicit Cast: E to E!T#}
<p>TODO</p>
{#header_open|Implicit Cast: Compile-Time Known Numbers#}
<p>When a number is {#link|comptime#}-known to be representable in the destination type,
it may be implicitly casted:
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
test "implicit casting large integer type to smaller one when value is comptime known to fit" {
const x: u64 = 255;
const y: u8 = x;
assert(y == 255);
}
{#code_end#}
{#header_close#}
{#header_open|Implicit Cast: compile-time known numbers#}
<p>TODO</p>
{#header_open|Implicit Cast: unions and enums#}
<p>Tagged unions can be implicitly cast to enums, and enums can be implicitly casted to tagged unions
when they are {#link|comptime#}-known to be a field of the union that has only one possible value, such as
{#link|void#}:
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
const E = enum {
One,
Two,
Three,
};
const U = union(E) {
One: i32,
Two: f32,
Three,
};
test "implicit casting between unions and enums" {
var u = U{ .Two = 12.34 };
var e: E = u;
assert(e == E.Two);
const three = E.Three;
var another_u: U = three;
assert(another_u == E.Three);
}
{#code_end#}
{#see_also|union|enum#}
{#header_close#}
{#header_open|Implicit Cast: union to enum#}
<p>TODO</p>
{#header_close#}
{#header_open|Implicit Cast: enum to union#}
<p>TODO</p>
{#header_close#}
{#header_open|Implicit Cast: T to *T when @sizeOf(T) == 0#}
<p>TODO</p>
{#header_open|Implicit Cast: Zero Bit Types#}
<p>{#link|Zero Bit Types#} may be implicitly casted to single-item {#link|Pointers#},
regardless of const.</p>
<p>TODO document the reasoning for this</p>
<p>TODO document whether vice versa should work and why</p>
{#code_begin|test#}
test "implicit casting of zero bit types" {
var x: void = {};
var y: *void = x;
//var z: void = y; // TODO
}
{#code_end#}
{#header_close#}
{#header_open|Implicit Cast: undefined#}
<p>TODO</p>
<p>{#link|undefined#} can be cast to any type.</p>
{#header_close#}
{#header_close#}