authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-11 19:34:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-11 19:34:58-04:00
log1a94dec50e3d8804a1f8191c34afc7e00283f55e
treeecefbf50d284f9140ebcf293e6e4af9d692d98fb
parent9b993565510ff210f0351019577b5c9bafbc7462
signaturelock-open Commit is signed but in an unrecognized format.

docs: finish initial documentation for implicit casts

closes #1514

1 files changed, 177 insertions(+), 28 deletions(-)

doc/langref.html.in+177-28
......@@ -4352,42 +4352,191 @@ test "float widening" {
43524352}
43534353 {#code_end#}
43544354 {#header_close#}
4355 {#header_open|Implicit Cast: Arrays#}
4356 <p>TODO: [N]T to []const T</p>
4357 <p>TODO: *const [N]T to []const T</p>
4358 <p>TODO: [N]T to *const []const T</p>
4359 <p>TODO: [N]T to ?[]const T</p>
4360 <p>TODO: *[N]T to []T</p>
4361 <p>TODO: *[N]T to [*]T</p>
4362 <p>TODO: *[N]T to ?[*]T</p>
4363 <p>TODO: *T to *[1]T</p>
4364 <p>TODO: [N]T to E![]const T</p>
4355 {#header_open|Implicit Cast: Arrays and Pointers#}
4356 {#code_begin|test#}
4357const std = @import("std");
4358const assert = std.debug.assert;
4359
4360// This cast exists primarily so that string literals can be
4361// passed to functions that accept const slices. However
4362// it is probably going to be removed from the language when
4363// https://github.com/ziglang/zig/issues/265 is implemented.
4364test "[N]T to []const T" {
4365 var x1: []const u8 = "hello";
4366 var x2: []const u8 = [5]u8{ 'h', 'e', 'l', 'l', 111 };
4367 assert(std.mem.eql(u8, x1, x2));
4368
4369 var y: []const f32 = [2]f32{ 1.2, 3.4 };
4370 assert(y[0] == 1.2);
4371}
4372
4373// Likewise, it works when the destination type is an error union.
4374test "[N]T to E![]const T" {
4375 var x1: anyerror![]const u8 = "hello";
4376 var x2: anyerror![]const u8 = [5]u8{ 'h', 'e', 'l', 'l', 111 };
4377 assert(std.mem.eql(u8, try x1, try x2));
4378
4379 var y: anyerror![]const f32 = [2]f32{ 1.2, 3.4 };
4380 assert((try y)[0] == 1.2);
4381}
4382
4383// Likewise, it works when the destination type is an optional.
4384test "[N]T to ?[]const T" {
4385 var x1: ?[]const u8 = "hello";
4386 var x2: ?[]const u8 = [5]u8{ 'h', 'e', 'l', 'l', 111 };
4387 assert(std.mem.eql(u8, x1.?, x2.?));
4388
4389 var y: ?[]const f32 = [2]f32{ 1.2, 3.4 };
4390 assert(y.?[0] == 1.2);
4391}
4392
4393// In this cast, the array length becomes the slice length.
4394test "*[N]T to []T" {
4395 var buf: [5]u8 = "hello";
4396 const x: []u8 = &buf;
4397 assert(std.mem.eql(u8, x, "hello"));
4398
4399 const buf2 = [2]f32{ 1.2, 3.4 };
4400 const x2: []const f32 = &buf2;
4401 assert(std.mem.eql(f32, x2, [2]f32{ 1.2, 3.4 }));
4402}
4403
4404// Single-item pointers to arrays can be implicitly casted to
4405// unknown length pointers.
4406test "*[N]T to [*]T" {
4407 var buf: [5]u8 = "hello";
4408 const x: [*]u8 = &buf;
4409 assert(x[4] == 'o');
4410 // x[5] would be an uncaught out of bounds pointer dereference!
4411}
4412
4413// Likewise, it works when the destination type is an optional.
4414test "*[N]T to ?[*]T" {
4415 var buf: [5]u8 = "hello";
4416 const x: ?[*]u8 = &buf;
4417 assert(x.?[4] == 'o');
4418}
4419
4420// Single-item pointers can be cast to len-1 single-item arrays.
4421test "*T to *[1]T" {
4422 var x: i32 = 1234;
4423 const y: *[1]i32 = &x;
4424 const z: [*]i32 = y;
4425 assert(z[0] == 1234);
4426}
4427 {#code_end#}
4428 {#see_also|C Pointers#}
43654429 {#header_close#}
43664430 {#header_open|Implicit Cast: Optionals#}
4367 <p>TODO: T to ?T</p>
4368 <p>TODO: T to E!?T</p>
4369 <p>TODO: null to ?T</p>
4370 {#header_close#}
4371 {#header_open|Implicit Cast: T to E!T#}
4372 <p>TODO</p>
4373 {#header_close#}
4374 {#header_open|Implicit Cast: E to E!T#}
4375 <p>TODO</p>
4431 <p>
4432 The payload type of {#link|Optionals#}, as well as {#link|null#}, implicitly cast to the optional type.
4433 </p>
4434 {#code_begin|test#}
4435const std = @import("std");
4436const assert = std.debug.assert;
4437
4438test "implicit casting to optionals" {
4439 const x: ?i32 = 1234;
4440 const y: ?i32 = null;
4441
4442 assert(x.? == 1234);
4443 assert(y == null);
4444}
4445 {#code_end#}
4446 <p>It works nested inside the {#link|Error Union Type#}, too:</p>
4447 {#code_begin|test#}
4448const std = @import("std");
4449const assert = std.debug.assert;
4450
4451test "implicit casting to optionals wrapped in error union" {
4452 const x: anyerror!?i32 = 1234;
4453 const y: anyerror!?i32 = null;
4454
4455 assert((try x).? == 1234);
4456 assert((try y) == null);
4457}
4458 {#code_end#}
43764459 {#header_close#}
4377 {#header_open|Implicit Cast: compile-time known numbers#}
4378 <p>TODO</p>
4460 {#header_open|Implicit Cast: Error Unions#}
4461 <p>The the payload type of an {#link|Error Union Type#} as well as the {#link|Error Set Type#}
4462 implicitly cast to the error union type:
4463 </p>
4464 {#code_begin|test#}
4465const std = @import("std");
4466const assert = std.debug.assert;
4467
4468test "implicit casting to error unions" {
4469 const x: anyerror!i32 = 1234;
4470 const y: anyerror!i32 = error.Failure;
4471
4472 assert((try x) == 1234);
4473 std.testing.expectError(error.Failure, y);
4474}
4475 {#code_end#}
43794476 {#header_close#}
4380 {#header_open|Implicit Cast: union to enum#}
4381 <p>TODO</p>
4477 {#header_open|Implicit Cast: Compile-Time Known Numbers#}
4478 <p>When a number is {#link|comptime#}-known to be representable in the destination type,
4479 it may be implicitly casted:
4480 </p>
4481 {#code_begin|test#}
4482const std = @import("std");
4483const assert = std.debug.assert;
4484
4485test "implicit casting large integer type to smaller one when value is comptime known to fit" {
4486 const x: u64 = 255;
4487 const y: u8 = x;
4488 assert(y == 255);
4489}
4490 {#code_end#}
43824491 {#header_close#}
4383 {#header_open|Implicit Cast: enum to union#}
4384 <p>TODO</p>
4492 {#header_open|Implicit Cast: unions and enums#}
4493 <p>Tagged unions can be implicitly cast to enums, and enums can be implicitly casted to tagged unions
4494 when they are {#link|comptime#}-known to be a field of the union that has only one possible value, such as
4495 {#link|void#}:
4496 </p>
4497 {#code_begin|test#}
4498const std = @import("std");
4499const assert = std.debug.assert;
4500
4501const E = enum {
4502 One,
4503 Two,
4504 Three,
4505};
4506
4507const U = union(E) {
4508 One: i32,
4509 Two: f32,
4510 Three,
4511};
4512
4513test "implicit casting between unions and enums" {
4514 var u = U{ .Two = 12.34 };
4515 var e: E = u;
4516 assert(e == E.Two);
4517
4518 const three = E.Three;
4519 var another_u: U = three;
4520 assert(another_u == E.Three);
4521}
4522 {#code_end#}
4523 {#see_also|union|enum#}
43854524 {#header_close#}
4386 {#header_open|Implicit Cast: T to *T when @sizeOf(T) == 0#}
4387 <p>TODO</p>
4525 {#header_open|Implicit Cast: Zero Bit Types#}
4526 <p>{#link|Zero Bit Types#} may be implicitly casted to single-item {#link|Pointers#},
4527 regardless of const.</p>
4528 <p>TODO document the reasoning for this</p>
4529 <p>TODO document whether vice versa should work and why</p>
4530 {#code_begin|test#}
4531test "implicit casting of zero bit types" {
4532 var x: void = {};
4533 var y: *void = x;
4534 //var z: void = y; // TODO
4535}
4536 {#code_end#}
43884537 {#header_close#}
43894538 {#header_open|Implicit Cast: undefined#}
4390 <p>TODO</p>
4539 <p>{#link|undefined#} can be cast to any type.</p>
43914540 {#header_close#}
43924541 {#header_close#}
43934542