// 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); // 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 + Default>() { let mut side_order = vec![]; let mut add_assignable: Wrapper = 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::(); custom_compound(); }