π€ Filed by Claude, not Vince β acting on his behalf via his GitHub credentials.
Background
#1232 asked for real structural (duck-type) verification of RBS interface-typed expectations (Hash::_Key, _ToAry, etc.) instead of a blanket :allow_unmatched_interface bypass. #1266 implements a v1 of that: ComplexType::Conformance now checks that the inferred type's method stack has a method for every name the interface directly declares, via ApiMap#get_method_stack.
That v1 is presence-only, as #1232 itself flagged as an acceptable known limitation for a first pass:
Generic interfaces (e.g. _Each[Elem], _Pair[K, V]) β presence-only checking of method names ignores the interface's own type parameters entirely; a v1 could ignore this (accept structurally by name only) and note it as a known limitation, or attempt matching each required method's parameter/return types too (more accurate, more complex, and recursive...)
The gap
Because the check only confirms a same-named method exists, it can't catch a method that exists but has the wrong shape:
- Wrong return type: a class with
def to_ary; "not an array"; end would now be treated as conforming to _ToAry, even though it doesn't actually return an Array.
- Wrong parameters: a class with
def eql?; true; end (zero-arg) would be treated as conforming to Hash::_Key, even though Hash::_Key#eql? expects one argument and calling it that way would raise ArgumentError at runtime.
Proposed direction
For each required method pin on the interface, in addition to checking presence via get_method_stack, compare:
- the candidate method's return type against the interface method's declared return type (itself potentially generic, e.g.
_ToAry[T]'s to_ary: () -> Array[T] β T needs to resolve against the interface's own type parameters as instantiated in expected)
- the candidate method's parameter arity/types against the interface method's declared parameters
This is naturally recursive β checking a method's own parameter/return types may itself involve interface types β so it should reuse ComplexType::Conformance rather than hand-rolling comparisons, with a base case (or depth/rule guard) to avoid infinite recursion on self-referential or mutually-referential interfaces.
Test coverage
spec/complex_type/conforms_to_spec.rb has two pending cases marked with this issue, added in #1266, that should be un-pended once this lands:
- a class with a same-named method but a mismatched return type should NOT conform
- a class with a same-named method but a mismatched arity should NOT conform
π€ Filed by Claude, not Vince β acting on his behalf via his GitHub credentials.
Background
#1232 asked for real structural (duck-type) verification of RBS interface-typed expectations (
Hash::_Key,_ToAry, etc.) instead of a blanket:allow_unmatched_interfacebypass. #1266 implements a v1 of that:ComplexType::Conformancenow checks that the inferred type's method stack has a method for every name the interface directly declares, viaApiMap#get_method_stack.That v1 is presence-only, as #1232 itself flagged as an acceptable known limitation for a first pass:
The gap
Because the check only confirms a same-named method exists, it can't catch a method that exists but has the wrong shape:
def to_ary; "not an array"; endwould now be treated as conforming to_ToAry, even though it doesn't actually return anArray.def eql?; true; end(zero-arg) would be treated as conforming toHash::_Key, even thoughHash::_Key#eql?expects one argument and calling it that way would raiseArgumentErrorat runtime.Proposed direction
For each required method pin on the interface, in addition to checking presence via
get_method_stack, compare:_ToAry[T]'sto_ary: () -> Array[T]βTneeds to resolve against the interface's own type parameters as instantiated inexpected)This is naturally recursive β checking a method's own parameter/return types may itself involve interface types β so it should reuse
ComplexType::Conformancerather than hand-rolling comparisons, with a base case (or depth/rule guard) to avoid infinite recursion on self-referential or mutually-referential interfaces.Test coverage
spec/complex_type/conforms_to_spec.rbhas twopendingcases marked with this issue, added in #1266, that should be un-pended once this lands: