Call/Return Pairs are balanced at runtime, not lexically. From all possible returns in a function, only a single one runs, and terminates the whole function. Every call site is paired, at runtime, with a single return that will return control to it, and the entire set of candidate returns are known at compile time, and the compiler checks all of this to report dumb mistakes.
This is not how Exceptions work, you can throw more than you can catch, and you can catch more than what can ever be thrown (this is generally harmless, just garbage code that never runs). Neither the number nor the types of throw/catch sites are kept in sync statically.
>a return can return to multiple different places depending on where the function was called from
Every single call site of a function is paired with all the returns of this function. The returns of a different function are paired with the call sites of that function, not the first. Unlike Exceptions, where every catch is a jump destination for every single throw of the same (dynamic) type across every single function beneath the catch on the call stack. That's literally an exponentially larger set than set of all the returns of a single function.
>why that would even be a desirable property
It's desirable because it gives static gaurantees.
Given a throw, you can't even know how much of the stack it would unwind, it can potentially unwind the entire stack if no compatible catch is above it on the call stack*. Exceptions can break through their abstraction boundaries and unwind the stack of a calling component that doesn't know about them. Exceptions are fundamentally dynamically typed Returns that you can forget about. That's as big a footgun as you can get without being deliberately a troll.
Given a catch, you can't even know where is all the places that can go to that catch (unlike a call site). Oh, there is the trivial answer of course : Every single function called in the try{...}, and every single function that those functions call, etc etc etc. Again, an intractable thing to reason about. So people don't, but they have to, the throw/catch pair is a single logical feature, their uses must be reasoned about and kept in sync in assumptions and consequences.
None of this is how a return works. If Structured Programming advocates saw Exceptions, they would be horrified. Even C's gotos don't allow you to jump out of a function.
* : (which, of course, is a dynamic property: in "if(...) then {Do_Something() catch(){...}} else{...}", only one branch will actually catch, one branch can crash the program, and none of this is visible to the compiler at write time)