The reasoning is tricky but it is a necessary hack if you have ordered type-checking: that is, while rustc employs HM type inference, it also has type-dependent resolution (things like fields and methods) and it traverses the function in AST order, so when it needs information, it can only know the results of HM inference for the parts of the function that come before in the source.
To solve this one must move to an order-independent constraint-based type-checking system: just like we have trait bounds checked in whatever order they happen to become known (i.e. enough inference information has been collected), we could have every single type-dependent construct kept around until it can be resolved.
This would be a significant rewrite, but strictly an improvement, if Rust didn’t have coercions.
The problem with coercions is they don’t primarily rely on HM inference (if you infer too deeply then you end up with a trait bound failing instead of a later coercion), although they do use it to understand e.g. function calls, their system is instead an “expected type hint” passed down from parent to child and transformed as needed.
This is the only kind of “eager top-down type propagation” rustc can do - the expected type reaches the leaves first, and only then HM can propagate what it might have learned from what was expected.
This hybrid system is problematic because of relatively determinism: how do you keep the same kinds of code working, i.e. how do you do out of order coercions withiut accidentally leaking some type further than they should reach (e.g. preventing a coercion in the only place it could be applied)?
Swift’s answer seems to be bactracking, and you can find discussions around (sadly I don’t have one on hand atm) about implicit type conversions resulting in potentially days of compilation time (backtracking being roughly of factorial time complexity while only linear space usage, so you can’t easily run out of memory, as I’ve had the recent unfortune of finding).
The most promising solution IMO is a boring fixed-point algorithm that repeatedly tries to resolve constraints it can be certain of, and when it runs out of those, just picks the first (in AST order) coercion to resolve to identity, which will hopefully unlock other constraints, without doing so in a way that would be backwards-incompatible.
This might be something we pursue in 2017 but not at the cost of compiler performance.