Operators

From lowest to highest precedence:

Level Operators Associativity
Logical OR or left
Logical AND and left
Equality ==, != left
Relational <, >, <=, >=, in, not in left
Bitwise OR | left
Bitwise XOR ^ left
Bitwise AND & left
Shift <<, >> left
Additive +, - left
Multiplicative *, /, % left
Power ** left
Unary -, not, ~ prefix

The bitwise operators bind more tightly than comparisons, unlike C's, so flags & MASK == 0 tests the result of &. They work on integers, not bool: &, |, and ^ give the promoted type of their operands, ~ the promoted type of its operand, and a shift the promoted type of the value shifted. A shift by a negative count, or by the width of that type or more (32 for int, 64 for i64), stops the program with a runtime error; a left shift wraps as other arithmetic does, and a right shift of a negative number keeps its sign. &=, |=, ^=, <<=, and >>= assign the result.

Parentheses override precedence. Logical operators emit C &&, ||, and !, so and and or stop evaluating as soon as the result is known. Power emits pow and is treated as an f64 expression. Its current left-associativity means 2 ** 3 ** 2 is parsed as (2 ** 3) ** 2.

Operand types are checked:

Operators Operands Result
+, -, *, / two numbers the promoted numeric type
+ two strings concatenated str
+ two arrays of the same type a new array with the elements of both
% two integers the promoted integer type
** two numbers f64
<, >, <=, >= two numbers, two chars, or two strings bool
==, != two numbers, two values of the same type, or a reference and null bool
+, -, *, /, % two values of a struct or enum that satisfies Add, Subtract, Multiply, Divide, or Remainder that type, from its method
and, or, not, unary - numbers or bool bool, or for - the promoted type of a number
unary - a struct or enum that satisfies Negate that type, from its method
in, not in a key and a map, an element and an array, or a char or str and a str bool

Strings compare by content, and < and the other orderings compare them byte by byte, as dictionaries order words in ASCII; arrays, maps, and structs compare by identity.

key in m asks whether a map has a key, x in values whether an array holds an element equal to x, and "ar" in text or 'a' in text whether a string contains a piece or character. not in is the opposite. in on arrays works for elements that are integers, bool, char, str, or plain enums.

Integer arithmetic wraps around on overflow, so 2147483647 + 1 as an int is -2147483648. Integer / truncates toward zero, and integer / or % by zero stops the program with a runtime error. Float division follows IEEE rules. As in C, integers narrower than an int are worked on as ints: the result of +, -, *, unary -, or / on two u8s is an int.

Built with --check-overflow, a program instead stops with a runtime error when the exact result of +, -, *, unary -, /, or abs does not fit its type, and when an integer is stored, passed, or returned as a type that cannot hold its value, as u8 small = count can be. Where wrapping around is meant, as in a hash, the wrapping operations say so and are never checked. A conversion written out, as in u8(count), always wraps around.

Relational operators bind more tightly than equality operators, so 0 == 1 < 2 is parsed as 0 == (1 < 2).