Fix unresolved method-level generic block parameters - #1326
Open
apiology wants to merge 4 commits into
Open
Conversation
each_with_object and inject-style methods with a method-level generic bound via an argument passed alongside a block never resolved that generic inside the block itself. resolve_generics_from_context dupped block parameters instead of resolving them when no per-parameter argument types were available, even though the generic had already been bound one level up.
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Aug 22, 2026
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Aug 22, 2026
apiology
commented
Aug 24, 2026
Cut the "even when... still route through" changelog framing from the resolve_generics_from_context comment down to the non-obvious constraint itself. Move the three new method-level-generic block-parameter specs out of the very long clip_spec.rb into a new spec/pin/callable_spec.rb, per review comment.
Extract arg_types[i] into arg_type_for_param and shrink the explanatory comment to one line, per review: prefer a well-named local over narrating the expression in a multi-line comment.
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Sep 5, 2026
Reorder so the comment states the action before the rationale, per review. Also replaces the ignore marker's reason. The previous wording blamed uniq, but the block param is untyped because Array#flatten is declared in core RBS as returning a bare Array: arr.flatten infers to ::Array where arr.compact infers to ::Array<::String>. With no element type on the receiver there is nothing for uniq's block param to bind to. No open PR covers this. The nearest two address different shapes: castwide#1326 is a method-level generic bound by an argument alongside a block, and castwide#1274 is a generic return type lost when the declaring method takes a block. Left as prose rather than citing a URL that does not match.
apiology
marked this pull request as ready for review
September 7, 2026 15:36
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was written by Claude Code on behalf of @apiology.
Problem
Enumerable#each_with_object is typed in core RBS as:
Uis a method-level generic bound by theobjargument passed toeach_with_object. Inside the block,arg_0(typedElem, the receiver's own generic) resolves correctly, butobj(typedU) resolves to no type at all:solargraph typecheck --level strongreportsUnresolved call to []=onmemo. The same shape of bug affects any method with a method-level generic bound via an argument passed alongside a block, e.g.Enumerable#inject.Root cause
Pin::Callable#resolve_generics_from_contextresolves a method-level generic from the method's own argument types into a sharedresolved_generic_valueshash, then recurses into the yielded block's parameter list to resolve that signature too. That recursive call is made with no per-parameter argument types available (nil), and the code took a shortcut for that case: itdup'd each block parameter instead of running it throughresolve_generics_from_context. So even thoughresolved_generic_values["U"]was already populated from the method's ownobjargument, the block's ownobjparameter (typedgeneric<U>) never picked it up.Fix
Always route block parameters through
resolve_generics_from_context, passingarg_types&.[](i)instead of skipping resolution whenarg_typesis nil.ComplexType::UniqueType#resolve_generics_from_contextalready handles a nil context type by falling back toresolved_generic_values[type_param] || self, so this is a pure bug fix with no behavior change for the case where argument types are available.Testing
Added spec cases in
spec/source_map/clip_spec.rbcoveringeach_with_object,inject, and a negative control (each_with_index, which has no method-level generic in its block signature and must be unaffected). Full suite: 0 failures.