monoton

Type coercion rules in Zig

The following small overview of type coercion rules in Zig is an amalgam of the official Zig documentation and a relevant exercise that is part of ziglings. It does not purport to be exhaustive and the official documentation should be consulted for in-depth explanations.

There exist three ways in which a type is coerced to another type:

  1. By declaring a variable.

    var a: u8 = 1;
    var b: u16 = a;
    
  2. By calling a function:

    fn foo(b: u16) void {
        _ = b;
    }
    
    var a: u8 = 1;
    foo(a);
    
  3. By using the @as builtin:

    var a: u8 = 1;
    var b = @as(u16, a);
    

Mutable to immutable

Non-constant types can be coerced to const types, thereby increasing the strictness.

var a: i32 = 1;
var b: *i32 = &a;
var c: *const i32 = b;

Error subsets to supersets

Error sets can be coerced from a subset to a superset.

const FirstError = error {
    SomethingWentWrong,
    SomethingElseWentWrong,
};

const SecondError = error {
    SomethingWentWrong
};

fn foo(err: SecondError) FirstError {
    return err;
}

foo(SecondError.SomethingWentWrong)

Integer widening

Integers can be coerced to wider types, iff every value of the old type can be represented by the new type.

var a: u8 = 255;
var b: u16 = a;
var c: u32 = b;
var d: u64 = c;
var e: u128 = d;

Unsigned integer to signed integer

Unsigned integers can be coerced to signed integers, iff every value of the old type can be represented by the new type.

var a: u8 = 255;
var b: i16 = a;

Float widening

Floats can be coerced to wider types, iff every value of the old type can be represented by the new type.

var a: f16 = 3.14;
var b: f32 = a;
var c: f64 = b;
var d: f128 = c;

Single-item pointers to arrays to slices

Single-item pointers pointing to an array can be coerced to many-item pointers.

var x: [3]u8 = [3]u8{1, 2, 3};
const y: []const u8 = &arr;

Single-item pointers to arrays to many-item pointers

Single-item pointers pointing to an array can be coerced to many-item pointers.

var x: [3]u8 = [3]u8{1, 2, 3};
const y: [*]const u8 = &arr;

Single-item pointers to single-item arrays

Single-item pointers can be coerced to pointers pointing to an array of length 1.

var x: i32 = 1234;
const y: *[1]i32 = &x;

Optionals

Payload types of optionals and null coerce to optionals.

var x: ?i32 = 1234; 
var y: ?i32 = null;

Error unions

Payload types of error unions and errors coerce to error unions.

var x: SomeError!i32 = 1234;             
var y: SomeError!i32 = SomeError.Failure;

Compile-time known numbers

Compile-time numbers coerce to types for which is it known during comptime that the number is representable in the new type.

const x: u64 = 255;
const y: u8 = x;

Tagged union to enum

Tagged unions coerce to enums:

const E = enum {
    a,
    b,
    c
};

const U = union(E) {
    a: f32,
    b: f32
};

var u = U{ .a = 3.14 };
var e: E = u;

Enums to tagged unions

Enums coerce to tagged unions when it is known during comptime that the tagged field has only one possible value.

const E = enum {
    a
};

const U = union(E) {
    a
};

const x = E.a;
const y: U = x;

Zero Bit Types

Zero bit types (e.g. void, u0, i0, etc.) coerce to single-item pointers.

var x: void = {};
var y: *void = x;

undefined

undefined can be coerced to any type.