it seems to me like the two blocks of code should be equivalent; or at least, that the first one could be turned into the second one automatically. This makes chaining functions somewhat harder. Is there a deep reason why the two are not equivalent? (I suspect something related to Drop but would love to hear the actual reason).
That's helpful indeed, thank you. If order of evaluation was right-to-left, this would work, then? It seems like &mut self should really be evaluated last, since it comes up as soon as you have a context + reference in it or something like that.
There is a special case for method calls that allows &mut self to be "borrowed last" in some cases. This is called Two-Phase Borrows. But currently, it works only if the "outer" call (f2 in your example) takes &mut self while the "inner" call (f1) takes &self.
This rule could be modified to allow code like yours, where both calls take &mut self. This was discussed as a possible extension in the RFC, but it was rejected for now because it would have added complexity, in both design and implementation. However, the RFC notes, "it would be possible to loosen the rules in the future."