Skip to content

§5 Expressions and Operators

CategoryOperators
Arithmetic+ - * / %
Comparison== != < > <= >=
Logical&& || !
Compound assignment+= -= *= /=
Type checkis
Borrow&expr &mut expr
Castexpr as Type

&& and || short-circuit. is performs a runtime type check and returns boolean.

Operator precedence: unary > multiplicative > additive > comparison > equality > && > || > assignment.

expr as Type performs an explicit numeric or pointer-shape conversion. The cast is postfix-bound (tighter than any binary operator) and left-associative — x as i32 as i64 parses as ((x as i32) as i64).

Source → TargetLLVM opNotes
int (any width) → wider intsextSign-extends
bool → wider intzexttrue → 1, not -1
int (any width) → narrower inttruncTruncates high bits
int (any width) → float/doublesitofpSigned integer to FP
boolfloat/doubleuitofptrue → 1.0, not -1.0
float/doubleint (any width)fptosiTruncates toward zero
f32float (double)fpextFP widening
float (double) → f32fptruncFP narrowing
*T*UbitcastPointer reinterpret
int*TinttoptrAddress-from-integer
*TintptrtointAddress-as-integer
same → sameidentityNo-op

expr as bool is rejected at the LLVM lowering level for any operand type — pointers, integers, and floats alike. The compiler emits a fix-it suggesting an explicit comparison: x != null for pointers, x != 0 for integers, x != 0.0 for floats. Reinterpreting bit patterns into i1 is almost always a bug; the comparison is the operation users actually want.

  • Source-level signedness is not tracked through casts. Sailfin’s i8/u8/i16/u16/i32/u32 annotations all collapse to LLVM i8/i16/i32, so 255_u8 as u64 lowers as sext and produces -1 instead of 255. Tracked in issue #295/#296 follow-ups.
  • Mixed int + float in a binary op (without an explicit cast) still silently widens to double — the architect-planned dominant_type tightening that would reject this rides on Slice E (number retirement). Workaround today: spell the cast (x as float + y or x + y as int). Tracked in issue #296.