Swift 5.8 で存在型(existential types)を用いているところに「any」を付けていないときに、コンパイルエラーにする
「Swift 5.8 の -enable-upcoming-feature
フラグを用いて、存在型(existential types)を用いているところに any
キーワードが付けられていない場合はコンパイルエラーにする」というタイトルにしたかったのですが、文字数制限に引っかかりました😇
本記事の内容は potatotips #81 iOS/Android開発Tips共有会(2023年2月21日 開催)の登壇資料(原稿)です。
Summary
- Swift 5.8 から「将来追加予定の言語改善への段階的な適用[1]」を行うためのコンパイラフラグ(
-enable-upcoming-feature
)などが追加される(SE-0362) - Swift Package(
Package.swift
)のターゲットで、存在型(existential types)を用いているところに any キーワードが付けられていない場合にコンパイルエラーとするには、「SwiftSetting.enableUpcomingFeature(_:_:)
」でname
に"ExistentialAny"
を指定する - Xcode プロジェクトのターゲットで、存在型(existential types)を用いているところに any キーワードが付けられていない場合にコンパイルエラーとするには、「Swift Compiler - Custom Flags」>「Other Swift Flags(
OTHER_SWIFT_FLAGS
)」に-enable-upcoming-feature ExistentialAny
を追加する
any
を付ける
存在型(existential types)を用いるところでは Swift 5.6 から、存在型(existential types)を示す際に any
キーワードを付けられるようになりました。ただ、Swift 5.6・5.7・5.8 では any
キーワードを付けていなくてもコンパイル時に警告やエラーとはなりません。しかし Swift 6 では any
キーワードを付けることが必須となります。
protocol Fruit { /* ... */ }
var fruit1: Fruit // ✅
var fruit2: any Fruit // ✅
Swift 5.8 では「将来追加予定の言語改善への段階的な適用」ができる
any
キーワードを付けることになる存在型(existential types)と、Opaque 型(opaque types)を取り扱う際に付けることがある some
キーワードはほぼ対の関係になっているため、コンパイルエラー等にならない「any
キーワードの付け忘れ」を Swift 6 がやってくる前の今のうちから無くしたいという気持ちがあります(Swift 6 では他にも破壊的変更が予定されているため、溜め続けてしまうと移行が大変になる未来が見えます)。
この「Swift 6 よりも前のうちから、この "any
キーワードの付け忘れ" のときはコンパイルエラーにしてほしい!」などの用途に使える、新しい機能が Swift 5.8 で追加されます。それが「将来追加予定の言語改善への段階的な適用[1:1]」です。
「将来追加予定の言語改善への段階的な適用」を行うには、Swift コンパイラに追加された -enable-upcoming-feature X
というようなコンパイラフラグを用います。「X
」には、適用させたい "将来追加予定の言語改善" の機能の名前を指定します。たとえば、今回の「存在型(existential types)を用いるところでは any
を付ける」ときは「-enable-upcoming-feature ExistentialAny
」とします。
-enable-upcoming-feature ExistentialAny
を付ける
それでは、この -enable-upcoming-feature ExistentialAny
を付けてみましょう。本記事では「Swift Package のターゲットに付ける」・「Xcode プロジェクトのターゲットに付ける」の2つの使用例を紹介します。
ExistentialAny
の適用を行う
Swift Package のターゲットで Swift Package のターゲットに対して「将来追加予定の言語改善への段階的な適用」を行うには、ターゲットの swiftSettings
で「SwiftSetting.enableUpcomingFeature(_:_:)
」を用います(swift-tools-version は 5.8 以降である必要があります)。
// swift-tools-version: 5.8
import PackageDescription
let package = Package(
name: "MyPackage",
products: [
.library(
name: "MyLibrary",
targets: ["MyTarget"]),
],
targets: [
.target(
name: "MyTarget",
swiftSettings: [
.enableUpcomingFeature("ExistentialAny", .when(configuration: .debug)),
]
),
]
)
SwiftSetting.enableUpcomingFeature(_:_:)
の第1引数の name
には文字列で "将来追加予定の言語改善" の機能の名前を指定します。今回は "ExistentialAny"
を渡しています。第2引数の condition
には BuildSettingCondition
を渡すことができます。
import Foundation
protocol Fruit { /* ... */ }
public struct MyTarget {
var fruit: Fruit!
/// "ExistentialAny" が有効のときは、
/// Use of protocol 'Fruit' as a type must be written 'any Fruit'
/// というコンパイルエラーになる。
/// `var fruit: (any Fruit)!` でコンパイルに成功する。
}
ExistentialAny
の適用を行う
Xcode プロジェクトのターゲットで Xcode プロジェクトのターゲットに対して「将来追加予定の言語改善への段階的な適用」を行うには、ターゲットから Swift コンパイラの設定を行います。
-enable-upcoming-feature
を使うには Swift 5.8(Xcode 14.3)以降が必要ですが、本記事公開時点で Xcode 14.3 は beta 版のため、スクリーンショットは Xcode 14.2 のものを用いています(Swift 5.8(Xcode 14.3)より前のままでは「Driver threw unknown argument: '-enable-upcoming-feature' without emitting errors.」というエラーとなり、ビルドできません)。
「将来追加予定の言語改善への段階的な適用」を行いたいターゲットの「Build Settings」にある、「Swift Compiler - Custom Flags」>「Other Swift Flags(OTHER_SWIFT_FLAGS
)」に -enable-upcoming-feature ExistentialAny
を追加します。
import SwiftUI
protocol Fruit { /* ... */ }
@main
struct MyApp: App {
var fruit: Fruit!
/// "ExistentialAny" が有効のときは、
/// Use of protocol 'Fruit' as a type must be written 'any Fruit'
/// というコンパイルエラーになる。
/// `var fruit: (any Fruit)!` でコンパイルに成功する。
var body: some Scene { /* ... */ }
}
(おまけ)すべての問題(issues)を一気に修正する
今回の「ExistentialAny
の適用を行う」を行った場合、プロジェクトによっては「Use of protocol '*' as a type must be written 'any *'」というエラーが多数表示されるかもしれません。
「Use of protocol '*' as a type must be written 'any *'」の場合は「Replace '*' with 'any *'」と修正提案を出してくれるため、Xcode の「Fix」ボタンを押していくとそれが適用されていきます。この数が多い場合はメニューの「Editor」>「Fix all issues」で一気にその提案を適用できます。
スクリーンショットは Xcode 14.2 のものです。
(しかし、「ExistentialAny」において Fruit?
や Fruit!
は (any Fruit)?
・(any Fruit)!
へと変更する必要がありますが、コンパイラが提案してくる修正が any Fruit?
・any Fruit!
のため、人間の手で直していく必要があります……。)
参考
Xcode 14.3 Beta Release Notes | Apple Developer Documentation
swift-evolution/0362-piecemeal-future-features.md at main · apple/swift-evolution
SwiftPodcast/Swift 将来追加予定の言語改善への段階的な適用.md at main · stzn/SwiftPodcast
-
原文は "Piecemeal adoption of upcoming language improvements"。日本語訳は stzn/SwiftPodcast をもとにした。 ↩︎ ↩︎
Discussion