There is so much counterintuitive information in the transition from Swift 5 to Swift 6. Many people don't understand the difference between Swift compiler versions and language modes. Swift 6 understandably introduces new compiler errors which are breaking changes. But these compiler errors appear in surprising places as well.
For example, the docs state "The Swift 6 language mode is opt-in . Existing projects will not switch to this mode without configuration changes." (Quote from “Migrating to Swift 6 | Documentation”) So when I built my SPM project, I did not expect strict concurrency checking to produce non-compilable errors. But it did. If Swift 6 language mode is supposed to be opt-in then why would this result in an error, instead of a warning?
Well it seems that the docs are incorrect because the errors went away after I opted out of Swift 6 language mode, and opted into Swift 5 language mode.
It seems that Xcode, SPM, and Swift CLI all handle this slightly differently.
For this reason, I'd like to crowd source some info about how Swift behaves differently depending on tools version, language mode, etc.
I would appreciate anyone willing to contribute to this spreadsheet.
Basically, there's more than one way to opt-in to the Swift 6 language mode, and you've done so without knowing it, as detailed in "Enabling The Swift 6 Language Mode"—
A Package.swift file that uses swift-tools-version of 6.0 will enable the Swift 6 language mode for all targets. You can still set the language mode for the package as a whole using the swiftLanguageModes property of Package.
This is why you have to opt your target back out of the Swift 6 language mode in your package manifest. You can instead downgrade the minimum tools version.
A Package.swift file that uses swift-tools-version of 6.0 will enable the Swift 6 language mode for all targets.
It's the swift package init command who creates the // swift-tools-version: 6.0 line in Package.swift file, not user. So for Swift Package Manager new projects we have opt-out, not opt-in.
This is a very good point. I did not add // swift-tools-version: 6.0 to my Package.swift. It was swift package init that did. It is very misleading for the docs to say that it is opt-in when it implicitly opts in for me without my knowledge.
Except it's not accurate. swift-tools-version determines the version SPM uses to parse the manifest exactly, and only newer versions get newer features. This includes things like language mode, but also things like the updated manifest model with the swiftLanguageMode label. Newer versions of SPM will happily parse and use packages with much older tools versions, and packages can require language versions newer than the tools version.
The Swift tools version declares the version of the PackageDescription library, the minimum version of the Swift tools and Swift language compatibility version to process the manifest, and the minimum version of the Swift tools that are needed to use the Swift package.
Yes, so I suppose I should've said it's incomplete, rather than inaccurate. It's a minimum in some ways, but in most it determines the exact version of behavior used to interpret the package.
Semi-related to the discussion here, I think it might be a good idea to think more about the tools-version and its relation to language mode, as well as revisit the concept more generally.
It was designed in a somewhat different world where language versions were happening more often and were generally something developers would adopt rather quickly. Similarly, on the package manager side, the version was mostly about additions to the API, rather than actually different behaviors preserved for backwards compatibility.