From 6c96746ab951d7393b247dea6beedb4d342f02bb Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 28 May 2026 09:58:33 +0900 Subject: [PATCH] Narrow Resolv::DNS resource methods by typeclass `Resolv::DNS#getresource` / `#getresources` / `#each_resource` / `#extract_resources` accept a typeclass argument (e.g. `Resolv::DNS::Resource::IN::MX`) that fully determines the returned resource subclass. The signatures returned the upper bound `Resolv::DNS::Resource`, dropping that information; callers using subclass-specific methods like `MX#exchange` then need a downcast. A bounded generic (`[T < Resolv::DNS::Resource] (..., singleton(T)) -> Array[T]`) would be the cleanest shape, but RBS does not currently accept a type variable inside `singleton(...)` (`Could not find ::T`). Fall back to per-subclass overloads for the `Resolv::DNS::Resource::IN::*` leaf types and `Generic`, with the previous wide overload kept as the trailing fallback (which also covers `Resource::ANY` and other classes under `Resolv::DNS::Query`). --- stdlib/resolv/0/resolv.rbs | 66 +++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/stdlib/resolv/0/resolv.rbs b/stdlib/resolv/0/resolv.rbs index 4798ef8f2..4ab7ee839 100644 --- a/stdlib/resolv/0/resolv.rbs +++ b/stdlib/resolv/0/resolv.rbs @@ -218,9 +218,37 @@ class Resolv::DNS # Iterates over all `typeclass` DNS resources for `name`. See #getresource for # argument details. # - def each_resource: (dns_name name, singleton(Resolv::DNS::Query) typeclass) { (Resolv::DNS::Resource) -> void } -> void - - def extract_resources: (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Query) typeclass) { (Resolv::DNS::Resource) -> void } -> void + def each_resource: (dns_name name, singleton(Resolv::DNS::Resource::IN::A) typeclass) { (Resolv::DNS::Resource::IN::A) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::AAAA) typeclass) { (Resolv::DNS::Resource::IN::AAAA) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::CNAME) typeclass) { (Resolv::DNS::Resource::IN::CNAME) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::HINFO) typeclass) { (Resolv::DNS::Resource::IN::HINFO) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::LOC) typeclass) { (Resolv::DNS::Resource::IN::LOC) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::MINFO) typeclass) { (Resolv::DNS::Resource::IN::MINFO) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::MX) typeclass) { (Resolv::DNS::Resource::IN::MX) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::NS) typeclass) { (Resolv::DNS::Resource::IN::NS) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::PTR) typeclass) { (Resolv::DNS::Resource::IN::PTR) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::SOA) typeclass) { (Resolv::DNS::Resource::IN::SOA) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::SRV) typeclass) { (Resolv::DNS::Resource::IN::SRV) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::TXT) typeclass) { (Resolv::DNS::Resource::IN::TXT) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::IN::WKS) typeclass) { (Resolv::DNS::Resource::IN::WKS) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Resource::Generic) typeclass) { (Resolv::DNS::Resource::Generic) -> void } -> void + | (dns_name name, singleton(Resolv::DNS::Query) typeclass) { (Resolv::DNS::Resource) -> void } -> void + + def extract_resources: (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::A) typeclass) { (Resolv::DNS::Resource::IN::A) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::AAAA) typeclass) { (Resolv::DNS::Resource::IN::AAAA) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::CNAME) typeclass) { (Resolv::DNS::Resource::IN::CNAME) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::HINFO) typeclass) { (Resolv::DNS::Resource::IN::HINFO) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::LOC) typeclass) { (Resolv::DNS::Resource::IN::LOC) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::MINFO) typeclass) { (Resolv::DNS::Resource::IN::MINFO) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::MX) typeclass) { (Resolv::DNS::Resource::IN::MX) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::NS) typeclass) { (Resolv::DNS::Resource::IN::NS) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::PTR) typeclass) { (Resolv::DNS::Resource::IN::PTR) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::SOA) typeclass) { (Resolv::DNS::Resource::IN::SOA) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::SRV) typeclass) { (Resolv::DNS::Resource::IN::SRV) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::TXT) typeclass) { (Resolv::DNS::Resource::IN::TXT) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::IN::WKS) typeclass) { (Resolv::DNS::Resource::IN::WKS) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Resource::Generic) typeclass) { (Resolv::DNS::Resource::Generic) -> void } -> void + | (Resolv::DNS::Message msg, dns_name name, singleton(Resolv::DNS::Query) typeclass) { (Resolv::DNS::Resource) -> void } -> void #