You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Attempting to use a value expression is a compiler error rather than promoting it to a temporary.
901
901
902
902
r[expr.compound-assign.operand-order]
903
-
Evaluation of compound assignment expressions depends on the types of the operators.
903
+
Evaluation of compound assignment expressions depends on the types of the operands.
904
904
905
-
r[expr.compound-assign.primitive-order]
906
-
If both types are primitives, then the modifying operand will be evaluated first followed by the assigned operand.
907
-
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.
905
+
r[expr.compound-assign.primitives]
906
+
If the types of both operands are known, prior to monomorphization, to be primitive, the right hand side is evaluated first, the left hand side is evaluated next, and the place given by the evaluation of the left hand side is mutated by applying the operator to the values of both sides.
907
+
908
+
```rust
909
+
# usecore::{num::Wrapping, ops::AddAssign};
910
+
#
911
+
traitEquate {}
912
+
impl<T> Equatefor (T, T) {}
913
+
914
+
fnf1(x: (u8,)) {
915
+
letmutorder=vec![];
916
+
// The RHS is evaluated first as both operands are of primitive
917
+
// type.
918
+
{ order.push(2); x }.0+= { order.push(1); x }.0;
919
+
assert!(order.is_sorted());
920
+
}
921
+
922
+
fnf2(x: (Wrapping<u8>,)) {
923
+
letmutorder=vec![];
924
+
// The LHS is evaluated first as `Wrapping<_>` is not a primitive
925
+
// type.
926
+
{ order.push(1); x }.0+= { order.push(2); (0u8,) }.0;
927
+
assert!(order.is_sorted());
928
+
}
929
+
930
+
fnf3<T:AddAssign<u8> +Copy>(x: (T,)) where (T, u8):Equate {
931
+
letmutorder=vec![];
932
+
// The LHS is evaluated first as one of the operands is a generic
933
+
// parameter, even though that generic parameter can be unified
934
+
// with a primitive type due to the where clause bound.
935
+
{ order.push(1); x }.0+= { order.push(2); (0u8,) }.0;
936
+
assert!(order.is_sorted());
937
+
}
938
+
939
+
fnmain() {
940
+
f1((0u8,));
941
+
f2((Wrapping(0u8),));
942
+
// We supply a primitive type as the generic argument, but this
943
+
// does not affect the evaluation order in `f3` when
944
+
// monomorphized.
945
+
f3::<u8>((0u8,));
946
+
}
947
+
```
908
948
909
949
> [!NOTE]
910
-
> This is different than other expressions in that the right operand is evaluated before the left one.
950
+
> This is unusual. Elsewhere left to right evaluation is the norm.
951
+
>
952
+
> See the [eval order test] for more examples.
911
953
912
954
r[expr.compound-assign.trait]
913
-
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).
914
-
A mutable borrow of the assigned operand is automatically taken.
955
+
Otherwise, this expression is syntactic sugar for using the corresponding trait for the operator (see [expr.arith-logic.behavior]) and calling its method with the left hand side as the [receiver] and the right hand side as the next argument.
915
956
916
-
For example, the following expression statements in `example` are equivalent:
957
+
For example, the following two statements are equivalent:
917
958
918
959
```rust
919
-
# structAddable;
920
960
# usestd::ops::AddAssign;
921
-
922
-
implAddAssign<Addable> forAddable {
923
-
/* */
924
-
# fnadd_assign(&mutself, other:Addable) {}
925
-
}
926
-
927
-
fnexample() {
928
-
# let (muta1, a2) = (Addable, Addable);
929
-
a1+=a2;
930
-
931
-
# let (muta1, a2) = (Addable, Addable);
932
-
AddAssign::add_assign(&muta1, a2);
961
+
fnf<T:AddAssign+Copy>(mutx:T, y:T) {
962
+
x+=y; // Statement 1.
963
+
x.add_assign(y); // Statement 2.
933
964
}
934
965
```
935
966
967
+
> [!NOTE]
968
+
> Surprisingly, desugaring this further to a fully qualified method call is not equivalent, as there is special borrow checker behavior when the mutable reference to the first operand is taken via [autoref].
969
+
>
970
+
> ```rust
971
+
> # usestd::ops::AddAssign;
972
+
> fnf<T:AddAssign+Copy>(mutx:T) {
973
+
> // Here we used `x` as both the LHS and the RHS. Because the
974
+
> // mutable borrow of the LHS needed to call the trait method
975
+
> // is taken implicitly by autoref, this is OK.
976
+
> x+=x; //~ OK
977
+
> x.add_assign(x); //~ OK
978
+
> }
979
+
> ```
980
+
>
981
+
> ```rust,compile_fail,E0503
982
+
> # usestd::ops::AddAssign;
983
+
> fnf<T:AddAssign+Copy>(mutx:T) {
984
+
> // We can't desugar the above to the below, as once we take the
985
+
> // mutable borrow of `x` to pass the first argument, we can't
986
+
> // pass `x` by value in the second argument because the mutable
987
+
> // reference is still live.
988
+
> <TasAddAssign>::add_assign(&mutx, x);
989
+
> //~^ ERROR cannot use `x` because it was mutably borrowed
990
+
> }
991
+
> ```
992
+
>
993
+
> ```rust,compile_fail,E0503
994
+
> # usestd::ops::AddAssign;
995
+
> fnf<T:AddAssign+Copy>(mutx:T) {
996
+
> // As above.
997
+
> (&mutx).add_assign(x);
998
+
> //~^ ERROR cannot use `x` because it was mutably borrowed
999
+
> }
1000
+
> ```
1001
+
936
1002
r[expr.compound-assign.result]
937
-
Like assignment expressions, compound assignment expressions always produce [the unit value][unit].
0 commit comments