Swift Digest
SE-0435 | Swift Evolution

Swift Language Version Per Target

Proposal
SE-0435
Authors
Pavel Yaskevich
Review Manager
Becca Royal-Gordon
Status
Implemented (Swift 6.0)

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(_:) という名称で提供されています。