Оптимизация хвостовых вызовов
Если вызов функции — последнее, что происходит, компилятор может переиспользовать текущий кадр стека вместо создания нового. Рекурсия превращается в цикл.
Условие — вызов в хвостовой позиции, то есть после его возврата не остаётся работы: return f(x) подходит, return f(x) + 1 — нет, ведь сложение ещё предстоит. Тогда адрес возврата сохранять незачем, и рекурсия любой глубины работает в постоянном объёме стека. В Scheme это требование стандарта, на нём держится выражение любой итерации через рекурсию. В C, C++ и Rust компиляторы делают это при включённой оптимизации, но без гарантий — поэтому тот же код может переполнить стек в отладочной сборке. В JavaScript её описали в ES6, но реализовал лишь Safari.