I believe that the language designers did some experimentation and designed the vtable struct so that calls to it can often be devirtualized. See this blog article for more details https://pithlessly.github.io/allocgate.html
This is correct, my understanding is devirtualization is quite sufficient in general and fine for Zig's allocator interface. The challenge/solution outlined in my article should not be read as "vtable bad!" but rather "vtable bad..if it means you lose ABI compatibility and have to copy struct data for ABI compatibility everywhere in the end"
If devirtualization does reliably occur then that's probably good enough. I find myself surprised that they would rely on compiler magic for that, it seems to go against the ethos of the language. But in the grand scheme of things, I guess it's a pretty minor cost.