Narrow is_a? checks joined by || to their union type - #64
Draft
apiology wants to merge 1 commit into
Draft
Conversation
FlowSensitiveTyping#process_or never computed any true-branch narrowing for an ||-joined condition, so a check like e.is_a?(Array) || e.is_a?(String) left e at its full declared type inside the if body instead of narrowing to Array | String. Add process_or_isa_union, which narrows only when both sides of the || are plain is_a? calls on the same variable, using the same process_facts/find_var/ComplexType.parse primitives process_isa already uses. Any other shape (different variables, or a side that isn't a plain is_a? call) is left unnarrowed rather than guessed at.
apiology
added a commit
that referenced
this pull request
Aug 22, 2026
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.
FlowSensitiveTyping#process_ornever computed any true-branch (positive) narrowing for an||-joined condition — its own comment notes "can't assume if an or is true that every single condition is true, so don't provide true ranges to assert facts on." That's correct in general, but it meansif e.is_a?(Array) || e.is_a?(String)never narrowseinside theifbody at all, even though the disjunction does guaranteeeis one ofArray | Stringthere.Example that fails
solargraph typecheck --level strongon master:This adds narrowing for the one case that's sound to infer generically: both sides of the
||are plainis_a?calls on the same variable. In that case the variable is narrowed to the union of the two checked types on the true branch. Any other shape — different variables on each side, or either side not a plainis_a?call — is left exactly as before (no narrowing), rather than guessing.Known limitation: a chain of three or more
is_a?checks (a.is_a?(X) || a.is_a?(Y) || a.is_a?(Z)) still gets no narrowing, because the AST nests as(X || Y) || Zand the outer left-hand side is an:ornode, not a:send, soparse_isareturns nil on it. This degrades to today's (no-narrowing) behavior rather than narrowing incorrectly, but a future PR could recurse to handle it.Adds three specs to
spec/parser/flow_sensitive_typing_spec.rb: the positive union case, a negative control (singleis_a?, unaffected), and a soundness control (different variables on each side of the||, still unnarrowed).