Fix UnreachableBranch on == against literal supertype (Symbol / Integer / String)#2223
Merged
Merged
Conversation
soutaro#2101 made the `==` (`for_receiver: true`) path of `literal_var_type_case_select` place every non-literal type into the falsy bucket only. That works for unrelated class types like the `Result` member of `Result | :some_symbol`, but it also drops literal *supertypes* such as `Symbol`, `Integer`, and `String` from the truthy bucket. As a result, code like def foo(symbol) # symbol: Symbol if symbol == :qux ... end end was reported as `Ruby::UnreachableBranch` even though `Symbol` obviously includes `:qux`. Narrow only when the literal type is a subtype of the receiver type so that supertypes of the literal still flow into the truthy branch (`Symbol == :qux` can be true), while unrelated class types remain falsy-only (`Result == :some_symbol` cannot). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7a8a79f to
d9b5604
Compare
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.
Summary
Fixes a regression introduced by #2101 (shipped in 2.0.0) where comparing a value of type
Symbol(orInteger/String) against a literal symbol/integer/string with==is incorrectly reported asRuby::UnreachableBranch.Closes #2222
Reproduction
a.rb:a.rbs:The same warning was emitted for
Integer == 1,String == "x", and the postfix-ifform.Cause
#2101 added
for_receiver: truetoLogicTypeInterpreter#literal_var_type_case_selectso that==against a literal could narrow union members likeResult | :some_symbolproperly:Resultcannot equal:some_symbol, so it should flow only into the falsy branch.The implementation, however, applied that rule to every non-literal type.
Symbol,Integer, andStringare non-literal class types but they include the corresponding literal values, so dropping them from the truthy bucket made theifbranch look unreachable.Fix
In
for_receiver: truemode, narrow only when the literal type is a subtype of the receiver type:Behavior matrix:
Symbol == :qux:quxSymbolResult == :some_symbol(unrelated class)Result(Result | :some_symbol) == :some_symbol:some_symbolResult:foo == :qux(literal vs literal):fooThe first row is the regression being fixed. The remaining rows match #2101's intent and continue to pass
smoke/narrowing-else.