April 18, 2019·4 min read·engineeringswiftcompilertooling

Swift 5.0.1 fixes failures in compiler tooling

Swift 5.0.1 addresses an indexing loop, debug-path remapping, and code-generation thread stack limits. These are changes to the tools that process programs before they run.

A compiler toolchain has to process programs that are not yet valid. An editor may ask it to index a half-written class, and an indexing operation must terminate even when the inheritance graph contains a cycle. Swift 5.0.1 includes a fix for precisely that problem. The April 18 release commit identifies the maintenance release, while its constituent changes show why a patch update matters beyond the language accepted by the compiler.

The superclass-indexing fix concerns code that decides whether a declaration is a unit-test case. The previous implementation repeatedly followed the superclass declaration until it found the expected test base or ran out of ancestors. That traversal assumed the chain would end. Circular inheritance invalidates the assumption and can keep the indexer walking indefinitely.

I find build and tooling delays the least pleasant part of working with Swift. A fix that makes an indexing query terminate is therefore relevant even when it adds no syntax. It restores a property that interactive development depends on, because source-processing services must tolerate the intermediate states created while editing.

Invalid input is part of the indexing workload

The regression tests make the failure concrete. They include a class that names itself as its superclass and pairs of classes that inherit from one another. Those declarations are not examples of legal inheritance. They are inputs the tool must survive while collecting symbols and relationships.

The implementation replaces the open-coded superclass loop with a superclass-walking operation. Its callback stops when it finds XCTestCase, while excluding the original declaration itself from being classified as a test merely because of its name. The change therefore addresses termination without discarding the distinction the indexing code was trying to make.

This is a different correctness requirement from accepting a valid executable program. A batch compiler can reject a malformed declaration and stop. An editor service often still needs information about nearby declarations, names, and relationships. If processing one broken declaration never returns, the editor loses information that could help its user repair the source.

The tests also cover protocol cycles. That broadens the regression coverage around inheritance processing without implying that those cycles have become legal. A test containing invalid source can be successful because the tested operation terminates and reports the expected symbols. The test requirement is about the service response, not permission to build the input into an application.

Worker threads have their own resource limits

Another included change increases the stack limit for LLVM code-generation threads. The commit explains that compilation could fail when those threads ran out of stack space. On macOS, the main thread has an 8 MB limit, while other threads had a 512 KB limit in the configuration being addressed. The change gives the code-generation threads an 8 MB limit.

Moving work to another thread can therefore change whether an algorithm finishes even when its source and intended result remain the same. The available stack is a property of that execution environment. A compiler working on a sufficiently demanding input may encounter the limit in its own implementation before it can produce a useful diagnostic or output file.

The fix does not establish that a generated program needs more stack. It concerns the compiler process producing that program. Keeping those two processes separate is necessary when interpreting a crash during a build. A failure inside LLVM code generation belongs to the development toolchain even if one particular application source file provokes it.

I prefer this kind of maintenance explanation to a generic claim that a compiler is more reliable. The resource limit and affected worker are identifiable. That gives a developer a reason to recognize the update when investigating a compilation failure with the corresponding symptoms.

Debug information includes dependency paths

Swift 5.0.1 also restores debug-prefix remapping during module creation. Its commit message says the remapping had been removed accidentally. The expanded regression test imports another module and checks the include path recorded for that module, in addition to checking the source filename.

Path remapping needs that broader coverage because a compiled artifact can describe more than the file currently being compiled. A build may supply a remapping rule for the source directory and another rule for a temporary module directory. Applying the first rule correctly does not prove that imported-module paths receive the second rule.

The release remains within the Swift 5.0 line established by the Swift 5 announcement. Its maintenance changes improve distinct stages of that toolchain. The indexing regression demonstrates why incomplete input belongs in compiler-tool tests, and the debug-information regression demonstrates why tests must inspect imported dependencies as well as the primary source. Both express observable requirements that a successful build of an ordinary application would leave untested.