The main transformation to enable tail calls is to replace the function call f
with a goto
, calling destructors on local variables, then replacing the original arguments of the current function with the arguments of f
. The normal borrow semantics for the return should therefore apply.
A tail call is only valid if there is nothing to be done in the caller after the call. This implementation checks this by first creating a node for become
in HIR, then later, in MIR, checks that the “basic block being branched into” either “has length zero” or “terminates with a return.” I assume that this “basic block being branched into” contains whatever follows the become
statement, and branches to another basic block if there’s anything more to do after the become
; otherwise falling into the cases mentioned.
Also notes the main reason tail calls haven’t been implemented yet: portability. They’re not supported in several targets, like WebAssembly, which is something that the Rust developers apparently won’t tolerate.