There is, surprisingly, a difference in evaluation order here.
When you use the *= operator on a primitive number, the right side is evaluated to obtain a value (of type u32 here), then the left side is evaluated to obtain the mutable place. The right side's temporary AsMut borrow has been dropped by the time the left side is evaluated.
When you use *= on a MulAssign, the left side is evaluated first, and its temporaries must therefore stay alive until the assignment is complete, which creates a borrow conflict when the right side is evaluated.
If both types are primitives, then the modifying operand will be evaluated first followed by the assigned operand. It will then set the value of the assigned operand's place to the value of performing the operation of the operator with the values of the assigned operand and modifying operand.
Note: This is different than other expressions in that the right operand is evaluated before the left one.
Otherwise, this expression is syntactic sugar for calling the function of the overloading compound assignment trait of the operator (see the table earlier in this chapter). A mutable borrow of the assigned operand is automatically taken.
You can observe this evaluation order behavior by running a program that uses the same types but has separate inputs to avoid the conflict: