I'm pretty sure it is type-checking, and quite probably also the dependency resolution overhead. After working for a bit on implementing Swift type checker from scratch in Swift itself and studying related talks/articles, I'm not quite sure if some of the early stage language design decisions were worth it.
There seems to be a consensus that existence of function overloads can blow up type checking time exponentially. There can be specialized solutions for cases, where arguments and return values in chained calls of overloaded operators are all the same. Say, 1 + 2 + 3 + 4 + 5 + 7 + 8 really shouldn't blow up, despite + having a ton of overloads, just need some smart detection of these cases. But in real world, the use of function and operator overloads is much more tricky and the complexity is NP-hard. Overall, I think operator and function overloading is more of a cosmetic feature with too big impact on the speed of the type checker. I like how Haskell's and PureScript's type checkers feel much more responsive, despite these languages having more advanced and powerful type systems: they just don't allow overloads in the same way that Swift does.
The other thing I didn't expect is that multi-file modules with no explicit intra-module imports also have impact on the incremental compilation speed. Check out the docs on Swift's dependency analysis:
The golden rule of dependency analysis is to be conservative. Rebuilding a file when you don't have to is annoying. Not rebuilding a file when you do have to is tantamount to a debug-time miscompile!
and
A file's "provides" set may be different before and after it is compiled -- declarations can be both added and removed, and other files may depend on the declarations that were added and the declarations that were removed. This means the dependency graph has to be updated after each file during compilation. (This is also why reusing build products is hard.)
The dependency analysis step wouldn't be needed at all if only we had to specify intra-module imports explicitly in every file. I understand that the initial motivation was to avoid header files altogether, but again, it was probably a step too far. I really like how top of the Swift file only needs to list external module imports, but now I also know that we pay a price for it. A minor change in a single file in a module can trigger an unexpected cascading rebuild of the whole module, especially as the existing dependency resolver tries to be conservative.
Obviously, it's too late to change any of these fundamental features, but I really hope that dev tools can become more advanced to show the impact of existing function overloads on the compilation time. Same with the dependency resolution, maybe we need to pay more attention to this area and improve the resolution algorithm, or at least get some debug tools that warn about cascading rebuilds.
It's interesting that llbuild can already provide some build process debug information, but I don't think this feature is available in SwiftPM or Xcode. As I continue working on Swift dev tools in my spare time, I'd be happy to get more input and suggestions and what else could be improved in this area.