diff --git a/build.zig b/build.zig index ca78bdf19797..cd25001eef07 100644 --- a/build.zig +++ b/build.zig @@ -155,7 +155,7 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void { ) catch unreachable; for (dep.system_libs.toSliceConst()) |lib| { const static_bare_name = if (mem.eql(u8, lib, "curses")) - ([]const u8)("libncurses.a") + @as([]const u8, "libncurses.a") else b.fmt("lib{}.a", lib); const static_lib_name = fs.path.join( diff --git a/doc/docgen.zig b/doc/docgen.zig index 07a7f23968b6..b25a9035018a 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -10,8 +10,8 @@ const testing = std.testing; const max_doc_file_size = 10 * 1024 * 1024; -const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt(); -const obj_ext = std.build.Target(std.build.Target.Native).oFileExt(); +const exe_ext = @as(std.build.Target, std.build.Target.Native).exeFileExt(); +const obj_ext = @as(std.build.Target, std.build.Target.Native).oFileExt(); const tmp_dir_name = "docgen_tmp"; const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext; diff --git a/doc/langref.html.in b/doc/langref.html.in index 3eb30c305862..627709ec84f9 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -712,7 +712,7 @@ test "init with undefined" { } {#code_end#}

- {#syntax#}undefined{#endsyntax#} can be {#link|implicitly cast|Implicit Casts#} to any type. + {#syntax#}undefined{#endsyntax#} can be {#link|coerced|Type Coercion#} to any type. Once this happens, it is no longer possible to detect that the value is {#syntax#}undefined{#endsyntax#}. {#syntax#}undefined{#endsyntax#} means the value could be anything, even something that is nonsense according to the type. Translated into English, {#syntax#}undefined{#endsyntax#} means "Not a meaningful @@ -920,7 +920,7 @@ fn divide(a: i32, b: i32) i32 { {#syntax#}f128{#endsyntax#}.

- Float literals {#link|implicitly cast|Implicit Casts#} to any floating point type, + Float literals {#link|coerce|Type Coercion#} to any floating point type, and to any {#link|integer|Integers#} type when there is no fractional component.

{#code_begin|syntax#} @@ -950,7 +950,7 @@ const nan = std.math.nan(f128); {#code_begin|obj|foo#} {#code_release_fast#} const builtin = @import("builtin"); -const big = f64(1 << 40); +const big = @as(f64, 1 << 40); export fn foo_strict(x: f64) f64 { return x + big - big; @@ -1652,7 +1652,7 @@ test "iterate over an array" { for (message) |byte| { sum += byte; } - assert(sum == usize('h') + usize('e') + usize('l') * 2 + usize('o')); + assert(sum == 'h' + 'e' + 'l' * 2 + 'o'); } // modifiable array @@ -2003,7 +2003,7 @@ test "variable alignment" { } } {#code_end#} -

In the same way that a {#syntax#}*i32{#endsyntax#} can be {#link|implicitly cast|Implicit Casts#} to a +

In the same way that a {#syntax#}*i32{#endsyntax#} can be {#link|coerced|Type Coercion#} to a {#syntax#}*const i32{#endsyntax#}, a pointer with a larger alignment can be implicitly cast to a pointer with a smaller alignment, but not vice versa.

@@ -2019,7 +2019,7 @@ var foo: u8 align(4) = 100; test "global variable alignment" { assert(@typeOf(&foo).alignment == 4); assert(@typeOf(&foo) == *align(4) u8); - const slice = (*[1]u8)(&foo)[0..]; + const slice = @as(*[1]u8, &foo)[0..]; assert(@typeOf(slice) == []align(4) u8); } @@ -2114,7 +2114,7 @@ const fmt = @import("std").fmt; test "using slices for strings" { // Zig has no concept of strings. String literals are arrays of u8, and // in general the string type is []u8 (slice of u8). - // Here we implicitly cast [5]u8 to []const u8 + // Here we coerce [5]u8 to []const u8 const hello: []const u8 = "hello"; const world: []const u8 = "世界"; @@ -2778,7 +2778,7 @@ test "simple union" { This turns the union into a tagged union, which makes it eligible to use with {#link|switch#} expressions. One can use {#link|@TagType#} to obtain the enum type from the union type. - Tagged unions implicitly cast to their enum {#link|Implicit Cast: unions and enums#} + Tagged unions coerce to their enum {#link|Type Coercion: unions and enums#}

{#code_begin|test#} const std = @import("std"); @@ -2795,7 +2795,7 @@ const ComplexType = union(ComplexTypeTag) { test "switch on tagged union" { const c = ComplexType{ .Ok = 42 }; - assert(ComplexTypeTag(c) == ComplexTypeTag.Ok); + assert(@as(ComplexTypeTag, c) == ComplexTypeTag.Ok); switch (c) { ComplexTypeTag.Ok => |value| assert(value == 42), @@ -2807,7 +2807,7 @@ test "@TagType" { assert(@TagType(ComplexType) == ComplexTypeTag); } -test "implicit cast to enum" { +test "coerce to enum" { const c1 = ComplexType{ .Ok = 42 }; const c2 = ComplexType.NotOk; @@ -2833,7 +2833,7 @@ const ComplexType = union(ComplexTypeTag) { test "modify tagged union in switch" { var c = ComplexType{ .Ok = 42 }; - assert(ComplexTypeTag(c) == ComplexTypeTag.Ok); + assert(@as(ComplexTypeTag, c) == ComplexTypeTag.Ok); switch (c) { ComplexTypeTag.Ok => |*value| value.* += 1, @@ -3943,7 +3943,7 @@ test "fn reflection" { However right now it is hard coded to be a {#syntax#}u16{#endsyntax#}. See #768.

- You can {#link|implicitly cast|Implicit Casts#} an error from a subset to a superset: + You can {#link|coerce|Type Coercion#} an error from a subset to a superset:

{#code_begin|test#} const std = @import("std"); @@ -3958,7 +3958,7 @@ const AllocationError = error { OutOfMemory, }; -test "implicit cast subset to superset" { +test "coerce subset to superset" { const err = foo(AllocationError.OutOfMemory); std.debug.assert(err == FileOpenError.OutOfMemory); } @@ -3968,7 +3968,7 @@ fn foo(err: AllocationError) FileOpenError { } {#code_end#}

- But you cannot implicitly cast an error from a superset to a subset: + But you cannot {#link|coerce|Type Coercion#} an error from a superset to a subset:

{#code_begin|test_err|not a member of destination error set#} const FileOpenError = error { @@ -3981,7 +3981,7 @@ const AllocationError = error { OutOfMemory, }; -test "implicit cast superset to subset" { +test "coerce superset to subset" { foo(FileOpenError.OutOfMemory) catch {}; } @@ -4008,7 +4008,7 @@ const err = (error {FileNotFound}).FileNotFound; It is a superset of all other error sets and a subset of none of them.

- You can implicitly cast any error set to the global one, and you can explicitly + You can {#link|coerce|Type Coercion#} any error set to the global one, and you can explicitly cast an error of the global error set to a non-global one. This inserts a language-level assert to make sure the error value is in fact in the destination error set.

@@ -4079,7 +4079,7 @@ test "parse u64" {

Within the function definition, you can see some return statements that return an error, and at the bottom a return statement that returns a {#syntax#}u64{#endsyntax#}. - Both types {#link|implicitly cast|Implicit Casts#} to {#syntax#}anyerror!u64{#endsyntax#}. + Both types {#link|coerce|Type Coercion#} to {#syntax#}anyerror!u64{#endsyntax#}.

What it looks like to use this function varies depending on what you're @@ -4218,10 +4218,10 @@ const assert = @import("std").debug.assert; test "error union" { var foo: anyerror!i32 = undefined; - // Implicitly cast from child type of an error union: + // Coerce from child type of an error union: foo = 1234; - // Implicitly cast from an error set: + // Coerce from an error set: foo = error.SomeError; // Use compile-time reflection to access the payload type of an error union: @@ -4598,10 +4598,10 @@ fn doAThing(optional_foo: ?*Foo) void { const assert = @import("std").debug.assert; test "optional type" { - // Declare an optional and implicitly cast from null: + // Declare an optional and coerce from null: var foo: ?i32 = null; - // Implicitly cast from child type of an optional + // Coerce from child type of an optional foo = 1234; // Use compile-time reflection to access the child type of the optional: @@ -4644,38 +4644,38 @@ test "optional pointers" { {#header_open|Casting#}

A type cast converts a value of one type to another. - Zig has {#link|Implicit Casts#} for conversions that are known to be completely safe and unambiguous, + Zig has {#link|Type Coercion#} for conversions that are known to be completely safe and unambiguous, and {#link|Explicit Casts#} for conversions that one would not want to happen on accident. There is also a third kind of type conversion called {#link|Peer Type Resolution#} for the case when a result type must be decided given multiple operand types.

- {#header_open|Implicit Casts#} + {#header_open|Type Coercion#}

- An implicit cast occurs when one type is expected, but different type is provided: + Type coercion occurs when one type is expected, but different type is provided:

{#code_begin|test#} -test "implicit cast - variable declaration" { +test "type coercion - variable declaration" { var a: u8 = 1; var b: u16 = a; } -test "implicit cast - function call" { +test "type coercion - function call" { var a: u8 = 1; foo(a); } fn foo(b: u16) void {} -test "implicit cast - invoke a type as a function" { +test "type coercion - @as builtin" { var a: u8 = 1; - var b = u16(a); + var b = @as(u16, a); } {#code_end#}

- Implicit casts are only allowed when it is completely unambiguous how to get from one type to another, + Type coercions are only allowed when it is completely unambiguous how to get from one type to another, and the transformation is guaranteed to be safe. There is one exception, which is {#link|C Pointers#}.

- {#header_open|Implicit Cast: Stricter Qualification#} + {#header_open|Type Coercion: Stricter Qualification#}

Values which have the same representation at runtime can be cast to increase the strictness of the qualifiers, no matter how nested the qualifiers are: @@ -4690,7 +4690,7 @@ test "implicit cast - invoke a type as a function" { These casts are no-ops at runtime since the value representation does not change.

{#code_begin|test#} -test "implicit cast - const qualification" { +test "type coercion - const qualification" { var a: i32 = 1; var b: *i32 = &a; foo(b); @@ -4699,7 +4699,7 @@ test "implicit cast - const qualification" { fn foo(a: *const i32) void {} {#code_end#}

- In addition, pointers implicitly cast to const optional pointers: + In addition, pointers coerce to const optional pointers:

{#code_begin|test#} const std = @import("std"); @@ -4713,10 +4713,10 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" { } {#code_end#} {#header_close#} - {#header_open|Implicit Cast: Integer and Float Widening#} + {#header_open|Type Coercion: Integer and Float Widening#}

- {#link|Integers#} implicitly cast to integer types which can represent every value of the old type, and likewise - {#link|Floats#} implicitly cast to float types which can represent every value of the old type. + {#link|Integers#} coerce to integer types which can represent every value of the old type, and likewise + {#link|Floats#} coerce to float types which can represent every value of the old type.

{#code_begin|test#} const std = @import("std"); @@ -4748,7 +4748,7 @@ test "float widening" { } {#code_end#} {#header_close#} - {#header_open|Implicit Cast: Arrays and Pointers#} + {#header_open|Type Coercion: Arrays and Pointers#} {#code_begin|test#} const std = @import("std"); const assert = std.debug.assert; @@ -4797,7 +4797,7 @@ test "*[N]T to []T" { assert(std.mem.eql(f32, x2, [2]f32{ 1.2, 3.4 })); } -// Single-item pointers to arrays can be implicitly casted to +// Single-item pointers to arrays can be coerced to // unknown length pointers. test "*[N]T to [*]T" { var buf: [5]u8 = "hello"; @@ -4823,15 +4823,15 @@ test "*T to *[1]T" { {#code_end#} {#see_also|C Pointers#} {#header_close#} - {#header_open|Implicit Cast: Optionals#} + {#header_open|Type Coercion: Optionals#}

- The payload type of {#link|Optionals#}, as well as {#link|null#}, implicitly cast to the optional type. + The payload type of {#link|Optionals#}, as well as {#link|null#}, coerce to the optional type.

{#code_begin|test#} const std = @import("std"); const assert = std.debug.assert; -test "implicit casting to optionals" { +test "coerce to optionals" { const x: ?i32 = 1234; const y: ?i32 = null; @@ -4844,7 +4844,7 @@ test "implicit casting to optionals" { const std = @import("std"); const assert = std.debug.assert; -test "implicit casting to optionals wrapped in error union" { +test "coerce to optionals wrapped in error union" { const x: anyerror!?i32 = 1234; const y: anyerror!?i32 = null; @@ -4853,15 +4853,15 @@ test "implicit casting to optionals wrapped in error union" { } {#code_end#} {#header_close#} - {#header_open|Implicit Cast: Error Unions#} + {#header_open|Type Coercion: Error Unions#}

The payload type of an {#link|Error Union Type#} as well as the {#link|Error Set Type#} - implicitly cast to the error union type: + coerce to the error union type:

{#code_begin|test#} const std = @import("std"); const assert = std.debug.assert; -test "implicit casting to error unions" { +test "coercion to error unions" { const x: anyerror!i32 = 1234; const y: anyerror!i32 = error.Failure; @@ -4870,23 +4870,23 @@ test "implicit casting to error unions" { } {#code_end#} {#header_close#} - {#header_open|Implicit Cast: Compile-Time Known Numbers#} + {#header_open|Type Coercion: Compile-Time Known Numbers#}

When a number is {#link|comptime#}-known to be representable in the destination type, - it may be implicitly casted: + it may be coerced:

{#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" { +test "coercing 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: unions and enums#} -

Tagged unions can be implicitly cast to enums, and enums can be implicitly casted to tagged unions + {#header_open|Type Coercion: unions and enums#} +

Tagged unions can be coerced to enums, and enums can be coerced 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#}:

@@ -4906,7 +4906,7 @@ const U = union(E) { Three, }; -test "implicit casting between unions and enums" { +test "coercion between unions and enums" { var u = U{ .Two = 12.34 }; var e: E = u; assert(e == E.Two); @@ -4918,20 +4918,20 @@ test "implicit casting between unions and enums" { {#code_end#} {#see_also|union|enum#} {#header_close#} - {#header_open|Implicit Cast: Zero Bit Types#} -

{#link|Zero Bit Types#} may be implicitly casted to single-item {#link|Pointers#}, + {#header_open|Type Coercion: Zero Bit Types#} +

{#link|Zero Bit Types#} may be coerced 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" { +test "coercion 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#} + {#header_open|Type Coercion: undefined#}

{#link|undefined#} can be cast to any type.

{#header_close#} {#header_close#} @@ -4976,7 +4976,7 @@ test "implicit casting of zero bit types" {
  • Some {#link|binary operations|Table of Operators#}
  • - This kind of type resolution chooses a type that all peer types can implicitly cast into. Here are + This kind of type resolution chooses a type that all peer types can coerce into. Here are some examples:

    {#code_begin|test#} @@ -5007,8 +5007,8 @@ test "peer resolve array and const slice" { comptime testPeerResolveArrayConstSlice(true); } fn testPeerResolveArrayConstSlice(b: bool) void { - const value1 = if (b) "aoeu" else ([]const u8)("zz"); - const value2 = if (b) ([]const u8)("zz") else "aoeu"; + const value1 = if (b) "aoeu" else @as([]const u8, "zz"); + const value2 = if (b) @as([]const u8, "zz") else "aoeu"; assert(mem.eql(u8, value1, "aoeu")); assert(mem.eql(u8, value2, "zz")); } @@ -5023,10 +5023,10 @@ test "peer type resolution: ?T and T" { } fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { if (c) { - return if (b) null else usize(0); + return if (b) null else @as(usize, 0); } - return usize(3); + return @as(usize, 3); } test "peer type resolution: [0]u8 and []const u8" { @@ -5815,7 +5815,7 @@ test "printf too many arguments" {

    Zig doesn't care whether the format argument is a string literal, - only that it is a compile-time known value that is implicitly castable to a {#syntax#}[]const u8{#endsyntax#}: + only that it is a compile-time known value that can be coerced to a {#syntax#}[]const u8{#endsyntax#}:

    {#code_begin|exe|printf#} const warn = @import("std").debug.warn; @@ -6185,7 +6185,7 @@ fn func() void {

    {#syntax#}await{#endsyntax#} is a suspend point, and takes as an operand anything that - implicitly casts to {#syntax#}anyframe->T{#endsyntax#}. + coerces to {#syntax#}anyframe->T{#endsyntax#}.

    There is a common misconception that {#syntax#}await{#endsyntax#} resumes the target function. @@ -6445,6 +6445,14 @@ comptime {

    {#header_close#} + {#header_open|@as#} +
    {#syntax#}@as(comptime T: type, expression) T{#endsyntax#}
    +

    + Performs {#link|Type Coercion#}. This cast is allowed when the conversion is unambiguous and safe, + and is the preferred way to convert between types, whenever possible. +

    + {#header_close#} + {#header_open|@asyncCall#}
    {#syntax#}@asyncCall(frame_buffer: []align(@alignOf(@Frame(anyAsyncFunction))) u8, result_ptr, function_ptr, args: ...) anyframe->T{#endsyntax#}

    @@ -7108,7 +7116,7 @@ test "field access by string" {

    {#syntax#}@frame() *@Frame(func){#endsyntax#}

    This function returns a pointer to the frame for a given function. This type - can be {#link|implicitly cast|Implicit Casts#} to {#syntax#}anyframe->T{#endsyntax#} and + can be {#link|coerced|Type Coercion#} to {#syntax#}anyframe->T{#endsyntax#} and to {#syntax#}anyframe{#endsyntax#}, where {#syntax#}T{#endsyntax#} is the return type of the function in scope.

    @@ -7827,7 +7835,7 @@ test "vector @splat" { const scalar: u32 = 5; const result = @splat(4, scalar); comptime assert(@typeOf(result) == @Vector(4, u32)); - assert(std.mem.eql(u32, ([4]u32)(result), [_]u32{ 5, 5, 5, 5 })); + assert(std.mem.eql(u32, @as([4]u32, result), [_]u32{ 5, 5, 5, 5 })); } {#code_end#}

    @@ -8025,7 +8033,7 @@ test "integer truncation" {

    If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#}, - then this is semantically equivalent to an {#link|implicit cast|Implicit Casts#}. + then this is semantically equivalent to {#link|Type Coercion#}.

    {#header_close#} @@ -8529,7 +8537,7 @@ pub fn main() void { {#header_close#} {#header_open|Cast Truncates Data#}

    At compile-time:

    - {#code_begin|test_err|integer value 300 cannot be implicitly casted to type 'u8'#} + {#code_begin|test_err|integer value 300 cannot be coerced to type 'u8'#} comptime { const spartan_count: u16 = 300; const byte = @intCast(u8, spartan_count); @@ -8665,7 +8673,7 @@ test "wraparound addition and subtraction" {

    At compile-time:

    {#code_begin|test_err|operation caused overflow#} comptime { - const x = @shlExact(u8(0b01010101), 2); + const x = @shlExact(@as(u8, 0b01010101), 2); } {#code_end#}

    At runtime:

    @@ -8683,7 +8691,7 @@ pub fn main() void {

    At compile-time:

    {#code_begin|test_err|exact shift shifted out 1 bits#} comptime { - const x = @shrExact(u8(0b10101010), 2); + const x = @shrExact(@as(u8, 0b10101010), 2); } {#code_end#}

    At runtime:

    @@ -9535,8 +9543,8 @@ const c = @cImport({

    {#syntax#}[*c]T{#endsyntax#} - C pointer.