Destructure block parameter groups and keep union-typed tuple elements in one position - #60
Draft
apiology wants to merge 4 commits into
Draft
Destructure block parameter groups and keep union-typed tuple elements in one position#60apiology wants to merge 4 commits into
apiology wants to merge 4 commits into
Conversation
A destructured group (|(a, b), c|) previously produced one garbage Parameter named with the raw sexp text and no local pins at all for the variables inside it, so every reference to them was an unresolved call. The group now registers as a single :mlhs Parameter (holding its position in the block signature), and each variable inside it becomes a local Parameter carrying an mlhs_path - the group's position plus the element index at each nesting level - typed by projecting the group's tuple type per position. typify_parameters also keeps its best partial result instead of discarding everything when a single yield type (e.g. each_with_object's unbound U generic) fails to resolve. SKIP=Solargraph: strong self-typecheck of the touched files carries 16 problems on the parent commit already (fallout of re-enabling tuple inference, which castwide#1223 mitigates); this diff nets that down to 15. PoC branch - the real PR should land atop castwide#1223.
…tion Substituting a generic type parameter with a union (e.g. Hash#each yielding [K, V] where K is 'String, Symbol' or 'String, nil') spliced the union's members into separate tuple positions, inflating Array(K, V) into a 3-arity tuple. That broke block destructuring (arity mismatch) and produced false 'Wrong argument type ... received Array(A, B, C)' errors at strong level. Both rebuild sites - resolve_param_generics_from_context and UniqueType#transform - now rebuild parameters per position, wrapping however many types a position's transformation produces back into that single position. Known limitation: the tag rendering is unchanged, so a multi-item position still PRINTS ambiguously (Array(String, Symbol, Integer)); positions survive in memory but not a to_s/parse round trip.
apiology
added a commit
that referenced
this pull request
Aug 17, 2026
# Conflicts: # lib/solargraph/pin/parameter.rb
The partial-result fallback added in this branch returned whatever
destructure_yield_types produced even when the yielded types could not
be matched to the block's parameters. In that fallback Ruby auto-splats
a single yielded value across several parameters, but the code assigns
the WHOLE value to position 0 and leaves the rest undefined - garbage
the previous all-or-nothing gate happened to discard.
Three real downstream sites regressed from "parameters untyped" to
"parameter 0 wrongly typed as the whole value":
hash[k] = v # Wrong argument type: expected String,
# received Array<Object, NilClass>
proc { |exception, try, elapsed, next_int| ... }
# exception expected Exception, received Array
Only keep a partial result when the positions genuinely correspond -
one yielded type per parameter, or a tuple whose arity matches the
parameter count. Otherwise fall back to undefined, as before.
Four specs pin the plain multi-parameter shapes (Hash#each pair,
Array-of-tuples, 4-parameter proc, non-matching arity).
apiology
added a commit
that referenced
this pull request
Aug 17, 2026
The #60 merge (86ccceb) brought in the partial-result fallback, which regressed three plate-spinner sites from 'parameters untyped' to 'parameter 0 typed as the whole yielded value' (jell.rb:35, my_asana_wip.rb:292, asana_retry.rb:57). Verified against this pin: the fix removes exactly those three errors and introduces none.
yield_types.first is ComplexType, nil; calling tuple?/all_params on it
directly failed strong self-typecheck (block.rb:84-85) once merged into
the integration branch, whose narrowing surfaces it. CI on the
integration merge reported exactly these two problems.
SKIP=Solargraph: the Overcommit hook wrapper errors out ('Solargraph
failed to run') in this worktree; the CI 'Solargraph / strong' job is
the authoritative gate.
apiology
added a commit
that referenced
this pull request
Aug 17, 2026
Fixes the two strong self-typecheck problems the previous merge introduced at pin/block.rb:84-85 (yield_types.first is nilable).
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.
|(name, count), memo|produced no local pins at all forname/count(every reference was an unresolved call), and aHash#eachblock over a union-keyed hash reported false "Wrong argument type ... received Array(String, nil, V)" errors because the key union's members were spliced into extra tuple positions.Two changes on top of castwide#1223: (1) a destructured group registers as one
:mlhsparameter holding its signature position; each variable inside becomes a local typed by projecting the group's tuple type per element index (nesting supported via an index path). (2) Generic resolution rebuilds type parameters per position, so a union binding one tuple slot stays one slot.Makes three previously-pending clip specs pass (un-pended here).
Known limitations: tag rendering of a multi-item position is still ambiguous (
Array(String, nil, Integer)), so positions survive in memory but not ato_s/parse round trip — follow-up. The partial-result fallback applies only when the yielded types correspond to the block's parameters one for one (a tuple destructured across them, or one yielded type per parameter); a single auto-splatted value whose arity cannot be matched leaves the parameters undefined rather than assigning the whole value to parameter 0.Test plan: 10 new specs (fail-before verified), including four pinning plain multi-parameter destructuring; full suite 1,610 examples, 0 failures.
🤖 This PR was written by Claude (Anthropic's AI assistant) on behalf of @apiology.
🤖 Generated with Claude Code
https://claude.ai/code/session_01H1FEjW6nMpZrWPmeWX9miT