Swift Language Version Per Target
01 何が問題だったのか
SwiftPM の Package.swift で Swift 言語バージョン(language mode)を指定する方法は、これまで swiftLanguageVersions によってパッケージ全体に対してのみ設定できました。しかし、この粒度ではメジャーな言語バージョンの更新に踏み切りにくいという問題がありました。
典型的な例が Swift 6 への移行です。Swift 6 言語モードでは strict concurrency がデフォルトで有効になり、これまで警告として報告されていたデータ競合に関する問題がエラーとして扱われるようになります。パッケージが複数のターゲットに分かれている場合、すべてのターゲットを同時に Swift 6 へ移行するのは現実的でないことも多く、パッケージ単位でしか言語バージョンを切り替えられないと、一部のターゲットだけ先に Swift 6 に対応させ、残りは従来の言語モードのまま段階的に移行するといった運用ができません。
ターゲットごとに Swift 言語バージョンを切り替えられれば、パッケージ全体の動作を保ったまま、準備の整ったターゲットから新しい言語バージョンに順次移行していくことができます。
02 どのように解決されるのか
SwiftSetting に、ターゲット単位で Swift 言語バージョンを指定するための swiftLanguageMode(_:) 設定を追加します。enableUpcomingFeature(_:) や enableExperimentalFeature(_:) と同じく、ターゲットの swiftSettings に並べて指定できます。
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "MyPackage",
targets: [
.target(
name: "LegacyTarget",
swiftSettings: [
.swiftLanguageMode(.v5),
]
),
.target(
name: "ModernTarget",
swiftSettings: [
.swiftLanguageMode(.v6),
]
),
],
swiftLanguageModes: [.v6]
)
この設定は swift-tools-version: 6.0 以上のマニフェストでのみ利用できます。ターゲットに swiftLanguageMode(_:) が指定されていればその値が優先され、指定がなければ従来通りパッケージレベルの swiftLanguageModes(または tools version に基づく既定値)にフォールバックします。
BuildSettingCondition も受け取れるため、特定のプラットフォームやビルド構成に限定して言語バージョンを上書きすることもできます。
この API により、パッケージ全体の言語バージョンはそのままに、先に新しい言語バージョンへ移行できるターゲットから順に swiftLanguageMode(.v6) を付けていくといった段階的な移行が可能になります。
なお、本Proposal本文では API 名として swiftLanguageVersion(_:) が示されていますが、レビューを経て実装では swiftLanguageMode(_:) という名称で提供されています。