Skip to content

Structural RBS interface conformance only checks method presence, not return/parameter typesΒ #1267

Description

@apiology

πŸ€– 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions