diff --git a/doc/langref.html.in b/doc/langref.html.in index 39d7e4449c..29e1105e28 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4352,42 +4352,191 @@ test "float widening" { } {#code_end#} {#header_close#} - {#header_open|Implicit Cast: Arrays#} -
TODO: [N]T to []const T
-TODO: *const [N]T to []const T
-TODO: [N]T to *const []const T
-TODO: [N]T to ?[]const T
-TODO: *[N]T to []T
-TODO: *[N]T to [*]T
-TODO: *[N]T to ?[*]T
-TODO: *T to *[1]T
-TODO: [N]T to E![]const T
+ {#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#} -TODO: T to ?T
-TODO: T to E!?T
-TODO: null to ?T
++ The payload type of {#link|Optionals#}, as well as {#link|null#}, implicitly cast to the optional type. +
+ {#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#} +It works nested inside the {#link|Error Union Type#}, too:
+ {#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#} -TODO
+ {#header_open|Implicit Cast: Error Unions#} +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: +
+ {#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#} -TODO
+ {#header_open|Implicit Cast: Compile-Time Known Numbers#} +When a number is {#link|comptime#}-known to be representable in the destination type, + it may be implicitly casted: +
+ {#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#} -TODO
+ {#header_open|Implicit Cast: unions and enums#} +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#}: +
+ {#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#} -TODO
- {#header_close#} - {#header_open|Implicit Cast: enum to union#} -TODO
- {#header_close#} - {#header_open|Implicit Cast: T to *T when @sizeOf(T) == 0#} -TODO
+ {#header_open|Implicit Cast: Zero Bit Types#} +{#link|Zero Bit Types#} may be implicitly casted to single-item {#link|Pointers#}, + regardless of const.
+TODO document the reasoning for this
+TODO document whether vice versa should work and why
+ {#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#} -TODO
+{#link|undefined#} can be cast to any type.
{#header_close#} {#header_close#}