77 lines
1.7 KiB
Rust
77 lines
1.7 KiB
Rust
// Test evaluation order of operands of the compound assignment operators
|
|
|
|
// run-pass
|
|
|
|
use std::ops::AddAssign;
|
|
|
|
enum Side {
|
|
Lhs,
|
|
Rhs,
|
|
}
|
|
|
|
// In the following tests, we place our value into a wrapper type so that we
|
|
// can do an element access as the outer place expression. If we just had the
|
|
// block expression, it'd be a value expression and not compile.
|
|
struct Wrapper<T>(T);
|
|
|
|
// Evaluation order for `a op= b` where typeof(a) and typeof(b) are primitives
|
|
// is first `b` then `a`.
|
|
fn primitive_compound() {
|
|
let mut side_order = vec![];
|
|
let mut int = Wrapper(0);
|
|
|
|
{
|
|
side_order.push(Side::Lhs);
|
|
int
|
|
}.0 += {
|
|
side_order.push(Side::Rhs);
|
|
0
|
|
};
|
|
|
|
assert!(matches!(side_order[..], [Side::Rhs, Side::Lhs]));
|
|
}
|
|
|
|
// Evaluation order for `a op=b` otherwise is first `a` then `b`.
|
|
fn generic_compound<T: AddAssign<T> + Default>() {
|
|
let mut side_order = vec![];
|
|
let mut add_assignable: Wrapper<T> = Wrapper(Default::default());
|
|
|
|
{
|
|
side_order.push(Side::Lhs);
|
|
add_assignable
|
|
}.0 += {
|
|
side_order.push(Side::Rhs);
|
|
Default::default()
|
|
};
|
|
|
|
assert!(matches!(side_order[..], [Side::Lhs, Side::Rhs]));
|
|
}
|
|
|
|
fn custom_compound() {
|
|
struct Custom;
|
|
|
|
impl AddAssign<()> for Custom {
|
|
fn add_assign(&mut self, _: ()) {
|
|
// this block purposely left blank
|
|
}
|
|
}
|
|
|
|
let mut side_order = vec![];
|
|
let mut custom = Wrapper(Custom);
|
|
|
|
{
|
|
side_order.push(Side::Lhs);
|
|
custom
|
|
}.0 += {
|
|
side_order.push(Side::Rhs);
|
|
};
|
|
|
|
assert!(matches!(side_order[..], [Side::Lhs, Side::Rhs]));
|
|
}
|
|
|
|
fn main() {
|
|
primitive_compound();
|
|
generic_compound::<i32>();
|
|
custom_compound();
|
|
}
|