What is the difference between the Swift 6 compiler and Swift 6 language mode?

5.7.1 · L3 · Interview

Predict first

What does this print in language mode 5 (with a Swift 6 compiler)?

#if compiler(>=6)
print("compiler")
#endif
#if swift(>=6)
print("swift")
#endif
  • compiler
  • swift
  • compiler then swift

Predict first

And in language mode 6?

#if compiler(>=6)
print("compiler")
#endif
#if swift(>=6)
print("swift")
#endif
  • compiler
  • swift
  • compiler then swift

Predict first

Does this compile in language mode 5?

struct Counter {
    static var count = 0
}
Counter.count += 1
  • Yes
  • No

Predict first

Does it compile in language mode 6?

struct Counter {
    static var count = 0
}
Counter.count += 1
  • Yes
  • No

Mental model. The compiler is the car, and the language mode is the speed limit sign. You can drive the new car under the old limit until you are ready.

The compiler version is the toolchain you build with (Xcode 16 ships Swift 6). The language mode (-swift-version, or the Swift Language Version build setting) selects which version of the language’s rules that compiler enforces. A Swift 6 compiler supports mode 5 and mode 6 (and older ones), and each module picks its own, so a Swift 6 app can depend on a package still in Swift 5 mode.

The big change in mode 6 is complete data-race safety checking, as errors: sending non-Sendable values across concurrency domains, and mutable global or static state that is not isolated, become compile errors rather than warnings or silence. In mode 5 the same code compiles. You can even test which you are in: #if compiler(>=6) asks about the compiler, #if swift(>=6) asks about the language mode. In a Swift 6 compiler building in mode 5, the first is true and the second is false.

The compiler is version 6, so compiler(>=6) is true. The language mode is still 5, so swift(>=6) is false.

Now both the compiler version and the language mode are 6.

Mode 5 does not enforce data-race safety for global and static mutable state.

A mutable static is shared state that any thread could touch, so mode 6 reports it is not concurrency-safe.

Common traps

  • Equating “updated Xcode” with “migrated to Swift 6”. Your modules stay in mode 5 until you change the setting.
  • Using #if swift(>=6) to test for the new compiler. It tests the language mode, which may still be 5.

They might follow up with

  • Where do you set it? Xcode’s Swift Language Version, or swiftLanguageModes on a SwiftPM target.
  • Can mixed-mode modules interoperate? Yes. Each module is checked by its own rules, and the boundaries use Sendable and isolation annotations.

Related questions

  • 5.7.2 What are upcoming features and experimental features, and how do they help a migration?
  • 5.7.3 How would you migrate a large codebase to Swift 6 without a freeze?

What are upcoming features and experimental features, and how do they… →