The code not compile with error "borrowed value does not live long enough, argument requires that foo is borrowed for 'a".
As I see, the compiler could've deduced lifetimes like so: lifetime_of(foo_mut_ref) = lifetime_of(foo) = lifetime_of(bar) = 'a. With this deduction, no lifetime constraints are violated.
So, why does the compiler give this error? What's wrong with the deduction above?
Both &'a mut T<'a> and &'a mut self are anti-patterns and red flags; they are almost never what you want (or what you think they do).
Here, it is a correct observation that you are tying all three lifetimes together by denoting everything with 'a But think about that: it can't possibly work, because the &'a mut self annotation combined with the fact that in fn bar<'a>(...) the lifetime 'a is a generic parameter means that the caller chooses this lifetime, and thus the extent of the borrow. However, you pass foo by value, meaning that it's necessarily destroyed at the end of the function, so if 'a was chosen to be longer than the fubcfion body, you would have a dangling pointer.
That's because of the invariance of mutable references and the covariance of shared references. Very roughly, shared references' lifetime can be "shrunk" if necessary to satisfy lifetime subset relationships; the same can't be done with mutable references.
Let me paraphrase your answer: In function fn bar<'a>, the caller can choose 'a beyond the scope of bar at call site. However, lifetime constraints can only be satisfied if 'a == lifetime_of(bar) ==> Compiler emit an error.
Do I understand it correctly?
Do you think, in this particular case, Rust's lifetime rules is a little too strict? I mean, no reference is dangling in this program, it only invalid because of Rust's rules.
Not really; the compiler must ensure that interfaces aren't affected by any implementations. If your code were allowed to compile, then you could modify it in a way that leads to a dangling pointer.
Anyway, the example seems contrived. What are you actually trying to do? There are likely better, easier, and more robust solutions to whatever actual problem you are having than asking for allowing dangling pointers.