Built-In Contract Conformances¶
Accepted
Accepted for V1 primitive, array, slice, range, and selected boxed dynamic conformances.
This document records the standard conformances that are available without user declarations. Some are ordinary prelude impls, some are prelude impls backed by compiler intrinsics, and some are compiler-provided facts for built-in type forms.
Primitive Numeric Conformances¶
Primitive numeric type identities are produced by the prelude factories documented in Built-In Types:
SignedInteger(bits)
UnsignedInteger(bits)
Float(bits)
The familiar names such as i32, u64, and f32 are aliases for those factory applications. The factory declarations live in the prelude, while the compiler constructs the canonical primitive Type identities and owns their layout, ABI, literal typing, arithmetic lowering, and target behavior.
Primitive numeric equality, ordering, and arithmetic conformances are ordinary generic prelude impls over those factories. Their operation bodies call compiler intrinsics, so static operator lowering remains direct primitive comparison or arithmetic after specialization.
Integer equality operators are cross-family and cross-width:
impl SignedInteger(comptime LBits: u8) as PartialEq(SignedInteger(comptime RBits: u8)) {
fn eq(self: *const Self, other: *const SignedInteger(RBits)) bool {
return Compiler.int_eq(Self, SignedInteger(RBits), self.*, other.*)
}
}
impl SignedInteger(comptime LBits: u8) as PartialEq(UnsignedInteger(comptime RBits: u8)) {
fn eq(self: *const Self, other: *const UnsignedInteger(RBits)) bool {
return Compiler.int_eq(Self, UnsignedInteger(RBits), self.*, other.*)
}
}
impl UnsignedInteger(comptime LBits: u8) as PartialEq(SignedInteger(comptime RBits: u8)) {
fn eq(self: *const Self, other: *const SignedInteger(RBits)) bool {
return Compiler.int_eq(Self, SignedInteger(RBits), self.*, other.*)
}
}
impl UnsignedInteger(comptime LBits: u8) as PartialEq(UnsignedInteger(comptime RBits: u8)) {
fn eq(self: *const Self, other: *const UnsignedInteger(RBits)) bool {
return Compiler.int_eq(Self, UnsignedInteger(RBits), self.*, other.*)
}
}
Integer ordering operators use the same four-pair matrix for PartialOrd(Other) and call compiler integer comparison intrinsics:
impl SignedInteger(comptime LBits: u8) as PartialOrd(UnsignedInteger(comptime RBits: u8)) {
fn partial_cmp(self: *const Self, other: *const UnsignedInteger(RBits)) ?Ordering {
return Compiler.int_partial_cmp(Self, UnsignedInteger(RBits), self.*, other.*)
}
}
The example above shows one pair; the prelude provides the signed/signed, signed/unsigned, unsigned/signed, and unsigned/unsigned PartialOrd impls.
Same-type integer equivalence and total ordering are also prelude impls:
impl SignedInteger(comptime Bits: u8) as Eq(SignedInteger(Bits)) {
}
impl UnsignedInteger(comptime Bits: u8) as Eq(UnsignedInteger(Bits)) {
}
impl SignedInteger(comptime Bits: u8) as Ord(SignedInteger(Bits)) {
fn cmp(self: *const Self, other: *const Self) Ordering {
return Compiler.int_cmp(Self, self.*, other.*)
}
}
impl UnsignedInteger(comptime Bits: u8) as Ord(UnsignedInteger(Bits)) {
fn cmp(self: *const Self, other: *const Self) Ordering {
return Compiler.int_cmp(Self, self.*, other.*)
}
}
isize and usize are aliases for target-selected signed and unsigned integer factory applications, so they receive the same conformances as their underlying primitive type identities.
Primitive floats implement same-width equality and partial ordering:
impl Float(comptime Bits: u8) as PartialEq(Float(Bits)) {
fn eq(self: *const Self, other: *const Self) bool {
return Compiler.float_eq(Self, self.*, other.*)
}
}
impl Float(comptime Bits: u8) as PartialOrd(Float(Bits)) {
fn partial_cmp(self: *const Self, other: *const Self) ?Ordering {
return Compiler.float_partial_cmp(Self, self.*, other.*)
}
}
Primitive floats do not implement Eq(Self) or Ord(Self) in V1. IEEE NaN breaks reflexive equality and total ordering. Mixed-width float comparison is not a contract conformance in V1; use explicit conversion or accepted numeric coercion where applicable.
Primitive integer arithmetic is provided by generic prelude impls over the signed/signed, signed/unsigned, unsigned/signed, and unsigned/unsigned family pairs for Add, Sub, Mul, Div, and Rem only when the result can be one of the existing operand types. Same-type operands preserve their type. Mixed concrete integer operands are accepted only when one operand type can represent every value of the other operand type; the result is that wider existing operand type.
If neither type can represent the other, no primitive arithmetic conformance exists for that pair. Primitive integer arithmetic does not synthesize mathematical-range result types such as u33 or i65.
impl SignedInteger(comptime LBits: u8)
as Add(UnsignedInteger(comptime RBits: u8), integer_operand_result(SignedInteger(LBits), UnsignedInteger(RBits)))
{
fn add(
self: *const Self,
other: *const UnsignedInteger(RBits),
) integer_operand_result(SignedInteger(LBits), UnsignedInteger(RBits)) {
return Compiler.int_add(
SignedInteger(LBits),
UnsignedInteger(RBits),
integer_operand_result(SignedInteger(LBits), UnsignedInteger(RBits)),
self.*,
other.*,
)
}
}
The example above shows one pair and an illustrative result-helper name. The helper is defined only when the left type represents all right values or the right type represents all left values, and it returns that existing operand type.
The prelude provides the accepted family matrix for each primitive integer arithmetic operator. If neither operand type represents the other, the operator expression is rejected.
Signed integers implement Neg(Self). Negating the minimum value of a signed integer follows the existing primitive signed overflow safety rule. Unsigned integers do not implement Neg in V1.
Primitive floats implement Add, Sub, Mul, and Div for same-width and widening combinations:
f32 op f32 -> f32
f32 op f64 -> f64
f64 op f32 -> f64
f64 op f64 -> f64
Primitive floats implement Neg(Self) and do not implement Rem in V1.
Mixed integer/float primitive arithmetic exists only when the integer operand can losslessly coerce to the float type under the existing numeric coercion rule. The result is the float type. Mixed operations that would require lossy conversion are rejected unless the programmer writes an explicit conversion.
Primitive arithmetic conformances are detailed in Arithmetic Contracts.
Bool, Void, and Pointer Conformances¶
bool implements same-type equality but not ordering:
bool implements PartialEq(bool)
bool implements Eq(bool)
void implements same-type equality but not ordering:
void implements PartialEq(void)
void implements Eq(void)
Pointer types implement same-type pointer-identity equality but not ordering:
*T implements PartialEq(*T)
*T implements Eq(*T)
*const T implements PartialEq(*const T)
*const T implements Eq(*const T)
Cross-mutability pointer comparison should use explicit coercion from *T to *const T, then same-type equality.
V1 does not provide default equality or ordering conformances for optionals, arrays, slices, or function values. Slice descriptor equality, element-wise sequence equality, optional payload equality, and function identity should be explicit in source or provided by named std helpers.
Array and Slice Conformances¶
Arrays and slices have compiler-provided, reflection-visible conformances:
[N]T implements Indexable(T)
[N]T implements MutableIndexable(T)
[N]T implements Sequence(T)
[N]T implements MutableSequence(T)
[]T implements Indexable(T)
[]T implements MutableIndexable(T)
[]T implements Sequence(T)
[]T implements MutableSequence(T)
[]const T implements Indexable(T)
[]const T implements Sequence(T)
[]const T does not implement mutable contracts.
Conformance is a type-level fact. Mutability is enforced by the available place or pointer:
const a: [128]f32 = make_readonly_frame()
var b: [128]f32 = make_frame()
use_readonly(&a) // ok
use_mutable(&b) // ok
Calling a mutable contract through a const place is invalid:
use_mutable(&a) // error
The compiler-provided implementations for arrays and slices should be visible to comptime reflection and tooling, while still lowering to efficient primitive operations.
Range Conformances¶
Range(T) and RangeInclusive(T) are prelude value types produced by range syntax outside slicing contexts. They implement value-yielding Iterable(T) for integer endpoint types in V1:
Range(T) implements Iterable(T)
RangeInclusive(T) implements Iterable(T)
Ranges do not implement Sequence(T) in V1. Sequence(T) is location/indexing based and inherits pointer-yielding Iterable(*const T), while range iteration computes values.
Boxed Dynamic Conformances¶
The required V1 boxed dynamic forwarding surface is closed:
Box(dyn Iterator(Item)) implements Iterator(Item)
Box(dyn Iterable(Item)) implements Iterable(Item)
Box(dyn MutableIterable(Item)) implements MutableIterable(Item)
These are ordinary required prelude impls for the specific erased owner types. They do not imply a general rule that Box(dyn C) implements C. See Boxed Iterator Forwarding.