I believe Scheme basically only uses the heap (which is necessary because of call/cc iirc).
Haskell uses a variation of a G machine (looks like a spineless tagless g machine to be specific). The way that works is that they convert your program into a giant lambda term and then they work on reducing it. This of course looks nothing like a traditional call stack, so you can replace that whole thing with the G machine. Recursion (at least of the non-tail recursive variety) will look like a lambda term slowly getting bigger in heap space.
And then I also heard of someone (I forget which language) talking about setting up some logic to look for stack overflows and then throw all the current stack onto a heap and then start over.
https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.54...
If the language is based on recursion, you can't just hope it happens commonly enough, it has to happen all the time, even for corecursive functions.
Except I've never been super clear on Haskell having TCE or not, because laziness means there are limited opportunities for it to even fire.