Skip to content

Fix Hash#fetch generic leak from unmatched RBS interface overloads - #65

Draft
apiology wants to merge 1 commit into
masterfrom
fix-issue-1227
Draft

Fix Hash#fetch generic leak from unmatched RBS interface overloads#65
apiology wants to merge 1 commit into
masterfrom
fix-issue-1227

Conversation

@apiology

Copy link
Copy Markdown
Owner

This PR was written by Claude Code on behalf of @apiology.

Fixes castwide#1227

Summary

Pin::Parameter#compatible_arg? rejected every argument against an RBS-interface-typed parameter (e.g. Hash#fetch's _Key) unless the argument's type was nominally included via CoreFills::INCLUDES. Since Hash#fetch's plain (no default, no block) overload takes a _Key-typed parameter, no overload of h.fetch(k) ever matched during argument-type inference, and Pin::Method#return_type fell back to unioning every overload's return type together — leaking the unbound generic X from the default-value and block overloads into the inferred type.

# @param h [Hash{String => Integer}]
# @return [Integer]
def fetch_it(h)
  h.fetch('a')
end

was reported as inferring ::Integer, generic<X> against the declared ::Integer return.

Fix

Add :allow_unmatched_interface to the rules passed to conforms_to? in compatible_arg?, matching the leniency TypeChecker already applies by default everywhere except its :alpha level (Rules#require_interfaces_resolved?). This is scoped to overload argument matching only — compatible_arg? has a single call site (Source::Chain::Call#inferred_pins).

Test plan

  • Added specs in spec/type_checker/levels/strong_spec.rb covering Hash#fetch (fixed) and Hash#[] (control, unaffected)
  • bundle exec rspec — 1626 examples, 0 failures, 60 pending (no new failures)
  • bundle exec rubocop on changed files — no offenses

Pin::Parameter#compatible_arg? rejected any argument against an
RBS-interface-typed parameter (e.g. Hash#fetch's _Key) unless the
argument's type was nominally included via CoreFills::INCLUDES. Since
Hash#fetch's non-block, non-default overload takes a _Key-typed
parameter, no overload of a plain h.fetch(k) call ever matched, and
Pin::Method#return_type fell back to unioning every overload's return
type together - including the unbound generic X from the two
overloads that require a default value or a block.

Add :allow_unmatched_interface to the rules passed to conforms_to? in
compatible_arg?, matching the leniency TypeChecker itself already
applies by default (see Rules#require_interfaces_resolved?) everywhere
except the :alpha level.

Fixes castwide#1227
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hash#fetch on Hash{Symbol => Class<X>} miscomputes generics when rbs >= 4.1.0

1 participant