Skip to content

Fix @yieldparam type lost on multi-overload block-form methods - #1290

Open
apiology wants to merge 1 commit into
castwide:masterfrom
apiology:fix-1289-overload-yieldparam
Open

Fix @yieldparam type lost on multi-overload block-form methods#1290
apiology wants to merge 1 commit into
castwide:masterfrom
apiology:fix-1289-overload-yieldparam

Conversation

@apiology

Copy link
Copy Markdown
Contributor

Summary

Fixes #1289.

Pin::Method#generate_signature always read @yieldparam/@yieldreturn tags from the method's own docstring, even when it was building the Signature for an @overload tag. Per YARD, @overload docstrings are self-contained, so when a method declared a block-form @overload alongside a second, plain @overload, the block-form overload's @yieldparam was silently dropped — the block-local variable resolved as untyped at the call site.

generate_signature now takes the docstring to read those tags from, and #signatures passes each overload tag's own docstring instead of the method's.

# @overload build
#   @return [String]
# @overload build
#   @yieldparam widget [String]
#   @return [void]
def build
  return 'hi' unless block_given?
  yield 'hi'
end

build do |w|
  w.upcase # was: Unresolved call to upcase
end

Test plan

  • bundle exec rspec (1443 examples, 0 failures)
  • bundle exec rubocop on changed files (clean)
  • Manually confirmed solargraph typecheck --level strong on the issue's repro now reports 0 problems

…ide#1289)

Pin::Method#generate_signature always read @yieldparam/@yieldreturn
tags from the method's own docstring, even when building a signature
for an @overload tag. Per YARD, @overload docstrings are
self-contained, so a block-form overload's @yieldparam was ignored
whenever the method had a second, plain overload declared alongside
it, and the block-local variable resolved as untyped at the call
site.

generate_signature now accepts the docstring to read those tags from,
and #signatures passes each overload tag's own docstring instead of
the method's.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LZghMwHqapBNWpbjUQdcFr
@apiology
apiology force-pushed the fix-1289-overload-yieldparam branch from 9214875 to 0b60c02 Compare August 12, 2026 17:51
@apiology
apiology marked this pull request as ready for review August 12, 2026 20:25
apiology added a commit to apiology/solargraph that referenced this pull request Aug 12, 2026
…k-form methods

Pin::Method#generate_signature always read @yieldparam/@yieldreturn
tags from the method's own docstring, even when it was building the
Signature for an @overload tag. Per YARD, @overload docstrings are
self-contained, so when a method declared a block-form @overload
alongside a second, plain @overload, the block-form overload's
@yieldparam was silently dropped - the block-local variable resolved
as untyped at the call site. generate_signature now takes the
docstring to read those tags from, and #signatures passes each
overload tag's own docstring instead of the method's.

Fixes castwide#1289

Clean auto-merge, no conflicts. Hit an unrelated environment issue on
the first commit attempt: this worktree's PATH has
/Users/broz/src/plate-spinner/bin ahead of ~/.rbenv/shims (a known
issue from earlier this session), so overcommit's pre-commit hook
resolved a bare `bundle` to that other project's toolchain and failed
to load the Gemfile. Retried via `direnv exec . env
PATH="/Users/broz/.rbenv/shims:$PATH" git commit`, which resolved
cleanly.

Verified: spec/pin/method_spec.rb,
spec/type_checker/levels/strong_spec.rb (145 examples, 0 failures, 5
pending), and a broader safety net - spec/type_checker, spec/pin,
spec/yard_map (479 examples, 0 failures, 15 pending).
@apiology

Copy link
Copy Markdown
Contributor Author

🤖 Filed by Claude, not Vince — acting on his credentials.

This fixes @yieldparam loss for YARD @overload-declared block-form methods, but our real-world case (Net::HTTP.start, an RBS-declared generic block-form overload) still fails on this branch — a different code path from the one this PR touches (Pin::Method#generate_signature/#signatures, YARD-only). Bisecting further: the failure is conditional on a keyword argument being present in the call. Net::HTTP.start('example.com') { |http| ... } (no kwargs) resolves http correctly; Net::HTTP.start('example.com', use_ssl: true) { |http| ... } does not. An equivalent plain YARD @generic/@yieldparam method (no RBS involved) is unaffected by adding a keyword arg to its call — so this looks specific to RBS generic-method-type translation, not a general kwarg-plus-block gap.

require 'net/http'

Net::HTTP.start('example.com', use_ssl: true) do |http|
  http.request(Net::HTTP::Get.new('/'))
end
$ bundle exec solargraph typecheck --level strong repro.rb
repro.rb:4: Unresolved call to request

Dropping use_ssl: true (call with no keyword arg at all) makes this 0 problems found on the same branch.

@apiology

Copy link
Copy Markdown
Contributor Author

🤖 Filed by Claude, not Vince — acting on his credentials.

Root cause isn't RBS-specific. Call#inferred_pins (lib/solargraph/source/chain/call.rb) matches call-site arguments to a signature's parameters purely by array index. A trailing keyword-arguments hash (use_ssl: true) is just another element in that array, so it gets checked against whatever positional parameter sits at that index — port here — instead of the kwrest parameter (**opt). The mismatch rejects the whole overload, so the block-form generic overload never matches and http falls back to untyped.

Confirmed this predates and is independent of this PR's 0b60c02e4 commit: it reproduces on master before that commit, and with a plain YARD **kwrest method that has no RBS involvement at all.

Fix and reproduction (matching the case above) are up at #1292.

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.

@yieldparam type on a block-form @overload isn't applied to the block-local variable at the call site

1 participant