You'll have to forgive my misunderstanding here, because I think we're talking past each other. Go's compilation model does not map cleanly onto Swift's compilation model, and the linked article talks about cycles in what would be inter-module dependency graphs. I don't believe that extending that logic to intramodule dependencies makes much sense in the context of our current incremental build setup. I further worry that optimizing for mostly/completely cycle-free intramodule dependencies is going to result in poor application architecture and may work to actually pessimize incremental builds by needlessly increasing the number of files required to lay out a cycle-free module.
Let's see a concrete example of this to check both of our understandings. Suppose you have two Swift files
// File 1
protocol P { /**/ }
struct A: Q { /**/ }
// File 2
protocol Q: P { /**/ }
Here, there's a cycle between the "symbols" (Swift does not model dependencies at this level, I'm going to use "names" from now on) across files. File1(A) -> File2(Q) -> File1(P). According to your reasoning, this cycle should always be broken, so we will introduce a third file
// File 1
protocol P { /**/ }
// File 2
protocol Q: P { /**/ }
// File 3
struct A: Q { /**/ }
File3(A) -> File2(Q) -> File1(P)
In an incremental build, you want to mostly optimize for the number of frontend jobs required to rebuild the average change, because the cost of creating new frontend processes and blocking parts of the intramodule build graph on them far outweighs most other costs. In addition, we must dynamically discover additional work during the incremental build, which results in observable compilation "waves". The driver therefore runs all incremental builds to a fixpoint, so the more waves we introduce the slower the entire build runs. In fact, the worst-case scenario for such a system is actually a linearization like this where a chain of dependencies can cause O(n) waves that completely serializes the incremental build schedule. I don't mean to make this out as some kind of especially common disaster scenario. Today, swiftdeps files result in quite dense dependency graphs, which helps to reduce the number of waves, but at the cost of over-compilation.
Linearization attacks the wrong problem in my opinion. You actually want to increase the granularity of dependency information, not require users to restructure the dependency graph itself. Because at the end of the day, it shouldn't matter whether the user spreads their app out in 3 files or 3000 files. Increasing the granularity of intramodule dependencies allows the driver to more effectively invalidate parts of the build graph, and may allow a future compiler to achieve incrementally inside of frontend jobs themselves.