upstream `ruby/rbs` PR — `Resolv::DNS`のタイプクラスによる戻り値型の絞り込み
upstreamのPRを準備する並行セッション(/Users/megurine/repo/ruby/rbs)への引き継ぎメモ。Mastodon解析サイクル(2026-05-28、789→2エラー)では、upstreamのPRが解消する一つのユーザー向けstdlib RBSギャップが残りました。CURRENT_WORKで参照されていたもう一つのギャップ(StringScanner#[])はupstreamにすでにマージ済みであることが判明しました。
1. StringScanner#[] — upstreamに取り込み済み、PRは不要
Section titled “1. StringScanner#[] — upstreamに取り込み済み、PRは不要”upstream stdlib/strscan/0/string_scanner.rbs:501(fcc16851時点のHEAD):
def []: (Integer | String | Symbol) -> String?バンドル済みのrbs-3.10.0(Rigorが現在使用しているバージョン)にはまだ狭い(Integer) -> String?のシグネチャしかなく、これがMastodonトライアルでsignature_parser.rbのscanner[:key]呼び出し箇所が誤検知する原因です。修正はupstream PRではなく、Rigor側でのrbs gemバージョン引き上げです。upstreamセッションのスコープ外です。
2. Resolv::DNS#getresources / #getresource / #each_resource — タイプクラスによる戻り値型の絞り込み
Section titled “2. Resolv::DNS#getresources / #getresource / #each_resource — タイプクラスによる戻り値型の絞り込み”実際のPRの対象。
実証的な根拠
Section titled “実証的な根拠”Mastodon app/validators/email_mx_validator.rb:49:
records = dns.getresources(domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }.exchangeはResolv::DNS::Resource::MX(およびIN::MXが継承)に定義されており、基底クラスのResolv::DNS::Resourceには定義されていません。現行のupstreamシグネチャ(stdlib/resolv/0/resolv.rbs:311):
def getresources: (dns_name name, singleton(Resolv::DNS::Query) typeclass) -> Array[Resolv::DNS::Resource]要素型が上限のResolv::DNS::Resourceになっており、タイプクラスが決定する部分型が失われています。特定のサブクラスを渡す呼び出し側(dns.getresources(name, IN::MX) / IN::A / IN::AAAAという形式——実際にはほぼこれしか使わない)は型精度が落ちてしまいます。
同じ形状の兄弟メソッド
Section titled “同じ形状の兄弟メソッド”いずれもstdlib/resolv/0/resolv.rbsのResolv::DNSクラス内:
| 行 | メソッド | インターフェース |
|---|---|---|
| 302 | getresource | 1件のResourceを返す |
| 311 | getresources | Array[Resource]を返す |
| 221 | each_resource | ブロックパラメータがResource |
| 223 | extract_resources | ブロックパラメータがResource |
fetch_resource(230行目)もタイプクラス引数を受け取りますが、Resourceを返す・ブロックに渡すわけではありません——ブロックには(Message, Name)が渡されます。スコープ外です。
提案する修正——有界ジェネリクスメソッド
Section titled “提案する修正——有界ジェネリクスメソッド”RBSは有界型パラメータをサポートしています(先例: core/random.rbs:97のdef rand: ... | [T < Numeric] (::Range[T]) -> T、core/encoding.rbs:136 / :182、core/dir.rbs:919、core/kernel.rbs:679 / :1407 / :1449 / :2279、core/marshal.rbs:154、core/ractor.rbs:557)。メソッドごとに1行のジェネリクスにするのが最もすっきりした形です。
def getresources: [T < Resolv::DNS::Resource] (dns_name name, singleton(T) typeclass) -> Array[T]
def getresource: [T < Resolv::DNS::Resource] (dns_name name, singleton(T) typeclass) -> T
def each_resource: [T < Resolv::DNS::Resource] (dns_name name, singleton(T) typeclass) { (T) -> void } -> void
def extract_resources: [T < Resolv::DNS::Resource] (Resolv::DNS::Message msg, dns_name name, singleton(T) typeclass) { (T) -> void } -> voidエッジケース — Resolv::DNS::Resource::ANY
Section titled “エッジケース — Resolv::DNS::Resource::ANY”Resolv::DNS::Resource::ANY < Resolv::DNS::Query(stdlib/resolv/0/resolv.rbs:833)はResolv::DNS::Resourceのサブクラスではありません——Query配下でResourceと並列の位置にあります。ANYをタイプクラスとして渡すと、マッチするリソース型の異種混合が返され、静的には裸のResourceエンベロープになります。有界パラメータ[T < Resolv::DNS::Resource]はANYを除外するため、旧来の広いオーバーロードがフォールバックとして並存します。
def getresources: [T < Resolv::DNS::Resource] (dns_name name, singleton(T) typeclass) -> Array[T] | (dns_name name, singleton(Resolv::DNS::Resource::ANY) typeclass) -> Array[Resolv::DNS::Resource](3つの兄弟メソッドも同じ形状。)
代替案 — サブクラスごとのオーバーロード
Section titled “代替案 — サブクラスごとのオーバーロード”有界ジェネリクスがupstreamのテストコーパスで扱いにくい推論出力を生む場合、明示的なオーバーロード方式は冗長さと引き換えに予測可能性をもたらします。完全なセットはResolv::DNS::Resource::IN::{A, AAAA, CNAME, HINFO, LOC, MINFO, MX, NS, PTR, SOA, SRV, TXT, WKS}とResolv::DNS::Resource::Genericサブクラス(およびANYフォールバック)をカバーします。約16オーバーロード行×4メソッド≈64行——許容範囲内ですが、ジェネリクス方式が機能するなら後者が望ましいです。
Rigor側の調整事項
Section titled “Rigor側の調整事項”- RigorはこのギャップのためのRigor独自の
sig/オーバーレイやstdlibオーバーレイプラグインを提供する予定はありません。判断(このノートの作成セッションのコミットメッセージを参照)はOptionD + A: upstreamに委ねてドキュメント化する——それまでの間、影響を受けるプロジェクト向けにユーザー側でのsignature_paths:/# rigor:disable回避策を案内する。 - Mastodonの残存エラーは
docs/CURRENT_WORK.mdの「2件の残存エラー」の項にResolv側ギャップとして記録されています。 - upstreamのPRがマージされ新しい
rbsgemがリリースされれば、Rigorのバンドルrbsバージョン引き上げによってMastodonの該当箇所が自動的に解消されます(StringScanner#[]の箇所も同時に)。
- upstream rbs HEAD: コミット
fcc16851(2026-05-28)にて調査。 - 比較対象のバンドル済み
rbs-3.10.0。 - Mastodon該当箇所:
app/validators/email_mx_validator.rb:49。 - CURRENT_WORK「Stdlib RBSカバレッジギャップパターン」項目。
© 2026 TypedDuck. Licensed under CC BY-SA 4.0.