Go has sub-second build times even on massive code-bases. Why? because it doesn't do a lot at build time. It has a simple module system, (relatively) simple type system, and leaves a whole bunch of stuff be handled by the GC at runtime. It's great for its intended use case.
When you have things like macros, advanced type systems, and want robustness guarantees at build time.. then you have to pay for that.
I can believe that, but even so it's caused by the type system monomorphising everything. When it use qsort from libc, you are using per-compiled code from a library. When you use slice::sort(), you get custom assembler compiled to suit your application. Thus, there is a lot more code generation going on, and that is caused by the tradeoffs they've made with the type system.
Rusts approach give you all sorts of advantages, like fast code and strong compile time type checking. But it comes with warts too, like fat binaries, and a bug in slice::sort() can't be fixed by just shipping of the std dynamic library, because there is no such library. It's been recompiled, just for you.
FWIW, modern C++ (like boost) that places everything in templates in .h files suffers from the same problem. If Swift suffers from it too, I'd wager it's the same cause.
I was all excited to conduct the "cargo check; mrustc; cc" is 100x faster experiment, but I think at best, the multiple is going to be pretty small.
But not having to is a win, as the monomorphised sorts are just much faster at runtime than having to do an indirect call for each comparison.
There are multiple caveats on providing this to users (we can't assume that macro invocations are idempotent, so the new behavior would have to be opt in, and this only benefits incremental compilation), but it's in our radar.
Not all programmers of course - if you look at std there are many places that split types into generic and non-generic parts so the compiler will reuse as much code as possible, but it does come at the cost of additional complexity. Worse if you aren't already aware of why they are doing it, the language does a marvellous job of hiding the reason that complexity is there. I'd wager a novice Rust programmer is as befuddled by it as a JavaScript programmer coming across his first free() call in C.
I have this dream of a language like Rust that makes the trade-off plain, so the programmer is always aware of "this is a zero cost abstraction - you're just making it plain via the type system your doing the right thing" and "I'm going to have to generate a lot of code for this". Then go a step further and put the types and source you want to export to other libraries in a special elf section in the .so so you don't need the source to link against it, then go another step further and make the programmer using the .so explicitly instantiate any stuff that does require a lot of code generated so he is aware of what is happening.
That said, I don't think it would help the compile time problem in most cases. C++ already does something close by forcing you to put exported stuff in .h files, and they ended up with huge .h files and slow compiles anyway.
Nevertheless doing that would make for a Rust like language, that, unlike Rust, supported an eco-system of precompiled libraries just like C does. Rust is so wedded to transparent monomorphisation it looks near impossible now.
Unfortunately that doesn't seem to ever be a scenario cargo will support out of the box.