Skip to content

Stub combine_same_type_arity_signatures - #1186

Merged
castwide merged 8 commits into
masterfrom
stub-combine-same-type-arity-signatures
May 13, 2026
Merged

Stub combine_same_type_arity_signatures#1186
castwide merged 8 commits into
masterfrom
stub-combine-same-type-arity-signatures

Conversation

@castwide

Copy link
Copy Markdown
Owner

This functionality needs to be stubbed while we debug an infinite loop bug in Ruby 3.x.

@castwide
castwide merged commit 6d8ce95 into master May 13, 2026
30 of 32 checks passed
apiology added a commit to apiology/solargraph that referenced this pull request Aug 2, 2026
combine_same_type_arity_signatures merges same-type-arity overload
signatures via Array#reduce, with an inner Array#flat_map over the
accumulator (old_signatures). On each element of old_signatures, the
block's non-merging branch returned the *entire* old_signatures array
(plus the new signature) instead of just that element's contribution.
Since flat_map concatenates every branch's return value, when N
existing signatures fail to merge with a new one, the result becomes
N*(N+1) elements instead of N+1 -- and that larger array becomes the
accumulator for the next reduce step, so the size compounds
multiplicatively with each additional signature.

The existing "bail out if n is not small" guard only checks the
length of the *initial* input array, so it doesn't catch this blowup,
which happens incrementally inside the reduce.

This method was stubbed out entirely in castwide#1186 ("Stubbing this method
while we debug an infinite loop bug in Ruby 3.x") as a stopgap. The
"infinite loop" was this exponential blowup: confirmed via rbspy live
Ruby-level stack sampling on a pre-stub checkout (v0.59), the process
was stuck in an identical stack at pin/method.rb:532-533 across
repeated samples, with RSS climbing continuously (past 11GB on macOS,
6.7GB+ on Linux x86_64) and no forward progress, when combining large
families of same-type-arity overloads pulled in via RBS collections
(e.g. Integer#+).

Fix: replace the per-element flat_map (which re-emits the whole
accumulator from within a block scoped to a single element) with a
single Array#map pass that independently combines or keeps each
element once, appending the new signature only if nothing merged.
This keeps the same O(n) per-signature, O(n^2) overall behavior the
original guard comment describes, without the accidental
multiplicative growth, and un-stubs the method so real signature
combination is safely re-enabled.

Adds a regression test using doubles that never successfully merge,
verifying the combined result size tracks the input size rather than
exploding.

Verified against current master (967c358):
- rspec spec/pin/method_spec.rb: 57 examples, 0 failures.
- Full CI typecheck recipe (solargraph typecheck --level strong)
  completes in ~5 minutes (no hang), finding 496 problems in 84/250
  files -- identical to the stubbed baseline, confirming no
  regression in typecheck output.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
apiology added a commit to apiology/solargraph that referenced this pull request Aug 2, 2026
combine_same_type_arity_signatures merges same-type-arity overload
signatures via Array#reduce, with an inner Array#flat_map over the
accumulator (old_signatures). On each element of old_signatures, the
block's non-merging branch returned the *entire* old_signatures array
(plus the new signature) instead of just that element's contribution.
Since flat_map concatenates every branch's return value, when N
existing signatures fail to merge with a new one, the result becomes
N*(N+1) elements instead of N+1 -- and that larger array becomes the
accumulator for the next reduce step, so the size compounds
multiplicatively with each additional signature.

The existing "bail out if n is not small" guard only checks the
length of the *initial* input array, so it doesn't catch this blowup,
which happens incrementally inside the reduce.

This method was stubbed out entirely in castwide#1186 ("Stubbing this method
while we debug an infinite loop bug in Ruby 3.x") as a stopgap. The
"infinite loop" was this exponential blowup: confirmed via rbspy live
Ruby-level stack sampling on a pre-stub checkout (v0.59), the process
was stuck in an identical stack at pin/method.rb:532-533 across
repeated samples, with RSS climbing continuously (past 11GB on macOS,
6.7GB+ on Linux x86_64) and no forward progress, when combining large
families of same-type-arity overloads pulled in via RBS collections
(e.g. Integer#+).

Fix: replace the per-element flat_map (which re-emits the whole
accumulator from within a block scoped to a single element) with a
single Array#map pass that independently combines or keeps each
element once, appending the new signature only if nothing merged.
This keeps the same O(n) per-signature, O(n^2) overall behavior the
original guard comment describes, without the accidental
multiplicative growth, and un-stubs the method so real signature
combination is safely re-enabled.

Adds a regression test using doubles that never successfully merge,
verifying the combined result size tracks the input size rather than
exploding.

Verified against current master (967c358):
- rspec spec/pin/method_spec.rb: 57 examples, 0 failures.
- Full CI typecheck recipe (solargraph typecheck --level strong)
  completes in ~5 minutes (no hang), finding 496 problems in 84/250
  files -- identical to the stubbed baseline, confirming no
  regression in typecheck output.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
castwide pushed a commit that referenced this pull request Aug 3, 2026
…res (#1238)

combine_same_type_arity_signatures merges same-type-arity overload
signatures via Array#reduce, with an inner Array#flat_map over the
accumulator (old_signatures). On each element of old_signatures, the
block's non-merging branch returned the *entire* old_signatures array
(plus the new signature) instead of just that element's contribution.
Since flat_map concatenates every branch's return value, when N
existing signatures fail to merge with a new one, the result becomes
N*(N+1) elements instead of N+1 -- and that larger array becomes the
accumulator for the next reduce step, so the size compounds
multiplicatively with each additional signature.

The existing "bail out if n is not small" guard only checks the
length of the *initial* input array, so it doesn't catch this blowup,
which happens incrementally inside the reduce.

This method was stubbed out entirely in #1186 ("Stubbing this method
while we debug an infinite loop bug in Ruby 3.x") as a stopgap. The
"infinite loop" was this exponential blowup: confirmed via rbspy live
Ruby-level stack sampling on a pre-stub checkout (v0.59), the process
was stuck in an identical stack at pin/method.rb:532-533 across
repeated samples, with RSS climbing continuously (past 11GB on macOS,
6.7GB+ on Linux x86_64) and no forward progress, when combining large
families of same-type-arity overloads pulled in via RBS collections
(e.g. Integer#+).

Fix: replace the per-element flat_map (which re-emits the whole
accumulator from within a block scoped to a single element) with a
single Array#map pass that independently combines or keeps each
element once, appending the new signature only if nothing merged.
This keeps the same O(n) per-signature, O(n^2) overall behavior the
original guard comment describes, without the accidental
multiplicative growth, and un-stubs the method so real signature
combination is safely re-enabled.

Adds a regression test using doubles that never successfully merge,
verifying the combined result size tracks the input size rather than
exploding.

Verified against current master (967c358):
- rspec spec/pin/method_spec.rb: 57 examples, 0 failures.
- Full CI typecheck recipe (solargraph typecheck --level strong)
  completes in ~5 minutes (no hang), finding 496 problems in 84/250
  files -- identical to the stubbed baseline, confirming no
  regression in typecheck output.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
apiology added a commit to apiology/solargraph that referenced this pull request Aug 12, 2026
Confirms combining many pins for the same method path completes
quickly rather than hanging - related to the concern that prompted
castwide#1186 and castwide#1195 (see comment in spec for why this
doesn't reproduce that specific bug, and where the precise regression
guard for it already lives).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LtM8dkYTeQEiyhFu1NLZCB
apiology added a commit to apiology/solargraph that referenced this pull request Sep 1, 2026
Cut docstrings and spec comments to the review's per-comment budget
(2-6 lines): the combine_duplicate_method_pins and
namespace_pin_for_generics docstrings, the alias-combination spec
comment, and the "combines many same-path pins" spec comment, which
had narrated the history of issues castwide#1186, castwide#1195, and castwide#1238 instead
of stating the current constraint. Also replaces "plain" in the
cross-file generics spec with what actually makes that fixture
plain: no @Generic tag, no @!parse stub.
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.

1 participant