Skip to content

Numeric Types

Accepted

Accepted for V1 primitive numeric coercions and explicit numeric conversions; advanced numeric APIs are deferred.

Numeric type names and literal forms are documented in Built-In Types. This page owns numeric coercion and explicit conversion semantics.

Numeric Coercions

V1 allows implicit integer widening when the destination integer type can represent every value of the source integer type:

const a: u8 = 250
const b: u16 = a    // ok
const c: usize = a  // ok when usize can represent every u8 value
const d: i16 = a    // ok because i16 can represent every u8 value

The coercion is rejected when the destination cannot represent the full source range:

const s: i32 = 5
const u: usize = s // error: usize cannot represent negative i32 values

const wide: u128 = 5
const n: usize = wide // error on targets where usize cannot represent every u128 value

Comptime-known integer values may coerce to an integer type when the specific value is representable in the destination type:

const x: u8 = 255 // ok

Out-of-range comptime-known integer values are rejected:

const y: u8 = 256 // error

comptime_int is exact within the V1 portable signed 256-bit range documented in Built-In Types. A comptime integer expression that exceeds the compiler-supported range is a compile error. comptime_int values remain comptime-only until an explicit annotation, expected type, or other context resolves them to a concrete integer type.

V1 also allows implicit float widening when the destination float type can represent every value of the source float type without rounding:

const a: f32 = 1.5
const b: f64 = a // ok

Float narrowing requires an explicit conversion:

const wide: f64 = 1.5
const narrow: f32 = wide // error

Integer-to-float coercion is allowed only when the destination float type can exactly represent every value of the source integer type:

const a: u8 = 250
const b: f32 = a // ok

The coercion is rejected when the destination float type cannot exactly represent every value of the source integer type:

const c: i32 = 16_777_217
const d: f32 = c // error: f32 cannot exactly represent every i32 value

Float-to-integer coercion is not implicit for runtime values. Use an explicit conversion that documents the rounding behavior.

Comptime-known integer values may coerce to integer destinations when the specific value is representable. Comptime-known floating-point values may coerce to concrete floating-point destinations with compile-time rounding to the destination format when the finite value is in range:

const a: f32 = 1.5 // ok
const b: u8 = 42   // ok
const c: f32 = 0.1 // ok, rounded to f32 at compile time

Comptime-known numeric coercions to integer destinations remain checked for exact representability, and finite floating-point overflow is rejected:

const d: u8 = 42.5 // error
const e: u8 = 256  // error

These are general type coercions, not indexing-specific rules. Indexing benefits from integer-to-usize coercions because index expressions have expected type usize.

Numeric Conversions

V1 includes explicit numeric conversion methods for primitive numeric values and comptime numeric values. These are compiler-known primitive methods in V1. User-defined types may define ordinary methods with the same names, but those methods do not become conversion hooks.

Future extension methods may move the public surface of these primitive conversions out of hardcoded compiler member lookup; see CEP-0011: General Extension Methods. The semantic operations still lower to compiler-known numeric conversions.

Operation Receiver Destination V1 behavior
to_int(T) integer or comptime_int integer Checked representability conversion.
truncate(T) integer or comptime_int integer Low-bit truncation.
to_float(T) integer, float, comptime_int, or comptime_float float Explicit conversion that may round.
trunc_to_int(T) float or comptime_float integer Float-to-integer conversion rounded toward zero.
floor_to_int(T) float or comptime_float integer Float-to-integer conversion rounded toward negative infinity.
ceil_to_int(T) float or comptime_float integer Float-to-integer conversion rounded toward positive infinity.
round_to_int(T) float or comptime_float integer Float-to-integer conversion rounded to nearest, ties to even.

Integer-to-integer checked conversion uses to_int(T):

const x: i32 = read_count()
const y: u8 = x.to_int(u8)

to_int(T) requires an integer destination type. It traps in Checked safety mode when the runtime value cannot be represented in T; in Unchecked safety mode, an out-of-range conversion is illegal behavior. For comptime-known values, out-of-range conversion is a compile error.

Integer truncation uses truncate(T):

const x: u16 = 0xff80
const a: u8 = x.truncate(u8) // 0x80 = 128
const b: i8 = x.truncate(i8) // 0x80 = -128

truncate(T) requires an integer destination type. It preserves the low T bit width of the source value's two's-complement representation. Signedness affects interpretation of the result, not which bits are kept. It does not trap for discarded high bits. For comptime_int, truncation uses the mathematical integer's low bits at the destination width.

Integer-to-float and float-to-float explicit conversion use to_float(T):

const f: f32 = big_count.to_float(f32)
const narrow: f32 = precise.to_float(f32)

For integer receivers, to_float(T) may round according to the destination float format. It traps in Checked safety mode if the integer magnitude is outside the finite representable range of the destination float; in Unchecked safety mode, that case is illegal behavior. For comptime-known integer values, finite range overflow is a compile error.

For float receivers, to_float(T) may round finite values. Finite values outside the destination finite range trap in Checked safety mode and are illegal behavior in Unchecked safety mode. NaN, +inf, and -inf convert to the destination's corresponding special values. Comptime-known finite overflow is a compile error.

Float-to-integer conversion names the rounding policy:

const a: i32 = x.trunc_to_int(i32)
const b: i32 = x.floor_to_int(i32)
const c: i32 = x.ceil_to_int(i32)
const d: i32 = x.round_to_int(i32)

trunc_to_int(T) rounds toward zero, floor_to_int(T) rounds toward negative infinity, ceil_to_int(T) rounds toward positive infinity, and round_to_int(T) rounds to nearest with ties to even. T must be an integer type.

For runtime float-to-integer conversions, NaN, infinity, and values outside the destination range after rounding trap in Checked safety mode and are illegal behavior in Unchecked safety mode. For comptime-known float values, invalid conversions are compile errors.

Boundaries

Deferred:

  • explicit wrapping arithmetic APIs or operators
  • checked-overflow arithmetic APIs
  • saturating arithmetic APIs
  • moving primitive numeric conversion methods to an extension-method surface once extension methods exist; see CEP-0011: General Extension Methods
  • f16, f80, and f128
  • related layout, ABI, literal, and constant-evaluation rules for deferred numeric types

Post-V1 arithmetic mode APIs are tracked by CEP-0013: Explicit Numeric Arithmetic Modes. Extended float families are tracked by CEP-0023: Extended Float Types.