That documentation is for obj.method() not Some::Path::method(obj) (and I was pretty loose with my language). This is the documentation for the latter. But (as it typical), I don't think it's nuanced enough to actually answer the question.
I wrote that when I thought you were talking about fully-qualified syntax and then wrote this section...
For one, it says
All function calls are sugar for a more explicitly fully-qualified syntax.
[...]
Refer to RFC 132 for further details and motivations.
However, those two resources don't agree with each other. The reference page linked to indicates that a fully-qualified syntax always starts with <Type> or <Type as Trait<...>>, where as the RFC allows a full path to a trait method. A path is only rewritten as <...> if it's a type, according to the RFC.
The RFC also doesn't discuss any algorithm for the path-based grammar though, so let's forge on and assume that the reference is right and a path to a trait is sugar for <_ as Trait<...>>. That would be this portion, but it's too vague to really be useful in this case.
In this case we have <_R as AddAssign<_L>>::add_assign(x, y) and we're asking "how does it infer _L and _R", and since it isn't documented and I haven't learned the compiler internals yet, this is the part where I would run off and throw a bunch of examples at the compiler to see if I can discern the behavior that way.
I haven't done that yet but maybe I will.
...but from your ticket I see you were talking about method call resolution after all.
The algorithm looks for a receiver of the candidate type, for each candidate. Not an implementer of the candidate type. So:
Build a candidate list: Foo, &Foo, &mut Foo
There are no Foo receivers in methods named foo; next candidate
impl Foo has a &Foo receiver in the method named foo
What it says is: "T's inherent methods (methods implemented directly on T)", and even more clearly wrong for traits: "trait implemented by T" (where T is the candidate receiver type).
I think that's just a restriction that the LHS must be a place expression? The desugaring could still be true, after the restriction to place expressions is checked.
Do you happen to know if there is an actual source-code-equivalent desugaring? I couldn't find one for == (sometimes it coerces like you called &(rhs as _) but sometimes &(rhs as _) is too ambiguous to compile in fully qualified syntax, for example) and the impression I got was "operator resolution is its own thing" from the issues, RFCs, and PRs I read (but I don't know the implementation myself).
with the method call <Self as AddAssign<Rhs>>::add_assign(&mut Self, Rhs).
Or, personally speaking, equivalently in the following two short forms:
Self: AddAssign<Rhs>
impl AddAssign<Rhs> for Self
So:
mri += 1 desugars to &mut i32 += i32 with <&mut i32 as AddAssign<i32>>::add_assign(&mut &mut i32, i32), or
&mut i32: AddAssign<i32>
impl AddAssign<i32> for &mut i32 which doesn't exist and the compiler emits error[E0368]: binary assignment operation += cannot be applied to type &mut {integer}
while AddAssign::add_assign(mri, 1) is the call AddAssign::add_assign(&mut i32, i32), i.e.
Self = i32, Rhs = i32
impl AddAssign<i32> for i32 does exist
they are not equivalent, since OP didn't stand on the perspective of Rust's type system.
That seems to be following the general principle that coercion sites are removed when type inference cannot proceed. The call has an unknown RHS type as long as the compiles still considers a coercion of the right hand side possible. If there's only a single applicable trait implementation, then it would choose that impl and the expected type is known for the tight hand side. So the compiler tries coercing the right hand side to that type, and deref coercion for references work.
On the other hand, if multiple applicable impls are still around, then the possibility for coercion of the RHS is removed, which helps type inference since after removing the coercion it knows that the trait impl must exactly match the RHS type. Which creates an error if the type does not match exactly but is merely coercible.
I mean the desugaring cannot be literally true (as in, all there is to it / how the compiler implements the operator), since += for primitive types is compiler-implemented and their AddAssign impls call +=, not the other way around. But that argument doesn't rule out that the += might behave exactly as if it was desugared to an AddAssign::add_assign call, so that the wax these AddAssign impls use += might be merely an implementation detail.
Oh wait, I might have seen that discussion. Was it that the order changes depending on whether it's built in or using the trait? Looks like something along those lines.. Rust Playground
As least that settles the question whether there could be any equivalent desugaring: No.
Update: The newest execution of compound assignment expression lies in the Reference book:
Evaluation of compound assignment expressions depends on the types of the operators.
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 assigment trait of the operator (see the table earlier in
this chapter). A mutable borrow of the assigned operand is automatically taken.