PC パソコン

Xcode「cannot convert value of type ‘KeyPath & Sendable>’」の原因と回避方法【Swift 6.4】

Xcode 27.0に含まれるApple Swift 6.4で、Swift 5言語モードのまま upcoming feature InferSendableFromCaptures を有効にすると、二重になったキーパス(nested key path)の型推論が変わり、従来コンパイルできたコードが cannot convert value of type ... で失敗することがあります。本記事では、Swift公式Issue #92832の最小再現例を基に、原因、発生条件、安全な回避手順、確認方法を整理します。

表示されるエラー

次のような、外側の KeyPath の値型として WritableKeyPath を持つAPIで発生します。

struct State {
    var value = 0
}

struct Paths {
    let value = \State.value
}

func observe<Value>(
    _ path: KeyPath<Paths, WritableKeyPath<State, Value>>
) {}

observe(\.value)

InferSendableFromCaptures を有効にして型チェックすると、代表的には次の診断が出ます。

error: cannot convert value of type
'KeyPath<Paths, any WritableKeyPath<State, Int> & Sendable>'
to expected argument type
'KeyPath<Paths, WritableKeyPath<State, Value>>'

note: arguments to generic parameter 'Value'
('any WritableKeyPath<State, Int> & Sendable'
and 'WritableKeyPath<State, Value>')
are expected to be equal

error: generic parameter 'Value' could not be inferred

原因

原因はアプリ側の State.value やジェネリック定義の単純な書き間違いではありません。InferSendableFromCaptures により、nested key pathの内側にある WritableKeyPath<State, Int> が any WritableKeyPath<State, Int> & Sendable という存在型として推論されます。その結果、関数が要求する具体的な WritableKeyPath<State, Value> と同一視できず、Value の推論まで失敗します。

Swift Evolution SE-0418は、メソッド参照やキーパスリテラルから Sendable を推論する仕組みを導入しました。この仕組み自体は並行処理の安全性を高めるものですが、公式Issue #92832では、Swift 5モードで機能フラグを有効にした場合のnested key pathに未解決の型推論問題が報告されています。

発生条件・対象バージョン

  • Xcode 27.0(Build 27A266a)
  • Apple Swift 6.4(swiftlang-6.4.0.34.1)
  • -swift-version 5、つまりSwift 5言語モード
  • -enable-upcoming-feature InferSendableFromCaptures を有効化
  • KeyPath<Outer, WritableKeyPath<Root, Value>> のようなnested key pathをジェネリックAPIへ渡す

修正版について:2026年10月4日時点でSwift公式Issue #92832はopenで、修正版は公式に明示されていません。Swift 6.4で修正された関連Issue #77488とは別のnested key pathケースです。「Swift 6.4ならすべて解決済み」とは判断しないでください。

推奨する解決手順

1. Swift 5モードでは機能フラグを一時的に外す

この機能を今すぐ必要としない場合は、公式Issueの再現で成功が確認されている構成へ戻すのが最も安全です。コマンドラインでは次の差になります。

# 成功する構成
xcrun swiftc -typecheck -swift-version 5 repro.swift

# Issueを再現する構成
xcrun swiftc -typecheck -swift-version 5 \
  -enable-upcoming-feature InferSendableFromCaptures \
  repro.swift

Xcodeでは対象ターゲットのBuild Settingsを確認し、SWIFT_UPCOMING_FEATURE_FLAGS または「Upcoming Feature: Infer Sendable From Captures」に相当する設定から、このフラグだけを外します。OTHER_SWIFT_FLAGS に直接書いている場合も同様です。Swift Package Managerでは、swiftSettings に追加した .enableUpcomingFeature("InferSendableFromCaptures") を一時的に除外します。

2. キャッシュではなく設定差を確認する

DerivedDataの削除だけでは、コンパイラの型推論を変えるフラグは解除されません。まずビルドログのSwiftコンパイラ引数を確認し、該当フラグが消えていることを確認してからClean Build Folderと再ビルドを行います。

代替策

明示的な型注釈を試す

SE-0418では文脈型がキーパスリテラルのsendability推論に影響します。そのため、キーパスを具体型のローカル変数へ先に束縛すると回避できる可能性があります。

let path: KeyPath<Paths, WritableKeyPath<State, Int>> = \.value
observe(path)

これはIssue #92832で修正済みと確認された公式解決策ではありません。実プロジェクトのジェネリック制約や型消去の有無で結果が変わるため、CIを含む同じSwiftツールチェーンで必ず検証してください。

nested key pathをAPI境界で分割する

外側の KeyPath と内側の WritableKeyPath を一度にジェネリック推論させず、内側を取り出してから WritableKeyPath<State, Value> を受け取る関数へ渡す設計も暫定策です。ただし公開APIの変更を伴うため、フラグを外せない場合に限定し、呼び出し側と型推論への影響をテストしてください。

確認方法

  1. 上記の最小再現コードを repro.swift として保存します。
  2. フラグなしのコマンドが終了コード0になることを確認します。
  3. フラグありで同じエラーを再現できることを確認します。
  4. プロジェクトからフラグを外し、ビルドログにも残っていないことを確認します。
  5. 通常ビルドとテストターゲットを再実行し、キーパスを利用するコードパスも実行します。

修正版が公開された後は、同じ最小再現コードを新しいツールチェーンで実行し、フラグを戻しても型チェックが成功することを確認してから本番設定へ反映してください。

注意点

  • as! や二重キャストで型エラーを隠す方法は、型安全性を損なうため推奨しません。
  • @unchecked Sendable を無関係なモデル型へ追加しても、このnested key pathの存在型不一致を根本的に解決するものではありません。
  • Swift 5言語モードとSwiftコンパイラのバージョンは別です。Xcode 27.0のSwift 6.4コンパイラで -swift-version 5 を指定した構成が今回の報告対象です。
  • 機能フラグを外すと、プロジェクト内の別コードが利用していたSendable推論も無効になります。並行処理チェックへの影響をテストしてください。

まとめ

このエラーは、Swift 5モードで InferSendableFromCaptures を有効にしたとき、nested key pathの内側が any ... & Sendable と推論され、ジェネリック引数 Value と一致しなくなるSwiftコンパイラの未解決問題です。現時点の推奨回避策は、影響する構成では該当upcoming featureを外し、公式Issueで修正版が確認できるまで最小再現テストを保持することです。

参照した公式情報