Add CustomDebugStringConvertible conformance to AnyKeyPath
01 何が問題だったのか
キーパス(\Theme.backgroundColor のようなリテラル)は、デバッグ時に print や LLDB の po でそのまま表示しても、中身を読み取れない情報しか得られませんでした。
struct Theme {
var backgroundColor: Color
var foregroundColor: Color
var overlay: Color {
backgroundColor.withAlpha(0.8)
}
}
print(\Theme.backgroundColor)
// Swift.KeyPath<Theme, Color>
出力されるのは型名だけで、同じ Theme 型の backgroundColor と foregroundColor の区別すらつきません。キーパスをログに出したり、ブレークポイントで値を確認したりしたい場面で、どのプロパティを指しているのかを知るすべがなく、デバッグ体験が大きく損なわれていました。
02 どのように解決されるのか
AnyKeyPath が CustomDebugStringConvertible に適合するようになり、debugDescription からキーパスをソース上の書き方に近い形で読み取れるようになりました。バイナリに残っているリフレクション情報やシンボル情報をたどりながら、キーパスのセグメントを順に文字列化します。理想的なケースではソース上の記述そのままに表示されます。
print(\Theme.backgroundColor)
// \Theme.backgroundColor
stored property に対するオフセットセグメントは、Mirror と同じ仕組みでプロパティ名を解決します。オプショナルチェインや強制アンラップに対応するセグメントには、それぞれ ? や ! が付きます。computed property のセグメントは、ゲッタの関数アドレスをシンボル検索し、デマングルして名前を取得します。
情報が得られない場合の表示
リフレクションメタデータがビルド時に無効化されていたり、リンカによってシンボル名がストリップされていたりすると、名前を解決できないことがあります。その場合は、そのセグメントに限って代替の表記でフォールバックします。
オフセットセグメントで型名とオフセットが得られる場合は、<offset [値] ([型])> の形式で出力します。
print(\Theme.backgroundColor)
// \Theme.<offset 0 (Color)>
computed property のシンボル検索が失敗した場合は、関数のアドレスを16進で、戻り値の型と合わせて出力します。
print(\Theme.overlay)
// \Theme.<computed 0xABCDEFG (Color)>
アドレスだけでは関数を特定しづらいため、型名が付加されて手がかりになるよう配慮されています。
出力フォーマットは保証されない
debugDescription という位置づけどおり、この出力形式はあくまでデバッグ用で、将来的に変更される可能性があります。たとえばコンパイラに新しいメタデータが追加されて名前解決の精度が上がったり、サブスクリプトキーパスの表示が .subscript() から [] に変わったり、引数の値まで含めて表示されるようになったりといった変更があり得ます。ログの突き合わせやテストの期待値として、この文字列を直接比較する使い方は避けるのが無難です。
また、新しい ABI 安定版での出力であり、古い OS へのバックデプロイはされません。
今後の展望
LLDB のフォーマッタ/サマリに対応できると、デバッグ時により豊かな情報を引き出せる可能性があります。バイナリには残っていないデバッグメタデータがデバッガ側で参照できるケースもあるためです。ただしキーパスのメモリレイアウトが ABI 安定でないことなどから実装の難度は高く、本提案のスコープ外として将来的な課題に位置づけられています。同様に、Windows や Linux 等でシンボル検索を機能させるため、DEBUG ビルドに限ってキーパス関数をグローバルにする、といった方向性も今後検討され得ます。