Skip to content

Add Range.from_node! for nodes known to carry a location - #113

Draft
apiology wants to merge 1 commit into
masterfrom
fix-range-from-node-narrowing
Draft

apiology wants to merge 1 commit into
masterfrom
fix-range-from-node-narrowing

Conversation

@apiology

Copy link
Copy Markdown
Owner

Claude: This PR was written by Claude Code on behalf of @apiology.

Problem: Solargraph::Range.from_node(node) is declared [Range, nil], and solargraph typecheck --level strong reports 24 call sites that chain off it or dereference an assigned local (.start, .ending, .contain?) with no guard - even though from_node only actually returns nil for a synthesized node with no real source location, and every one of these 24 sites passes a node freshly parsed from real source.

lib/solargraph/pin/base_variable.rb: Unresolved call to start on Range, nil

Solution: Added Range.from_node! - a non-nilable variant that raises ArgumentError instead of returning nil - and switched the 24 verified-safe call sites to it (flow-sensitive-typing node processors, Source#node_at/tree_at traversal, Pin::BaseVariable#assignment, Pin::Block#receiver, dstr children). One further marker (TypeChecker#call_problems) cleared as a downstream side effect. Left #from_node itself nilable, and left one site (Source#inner_folding_ranges) on the nilable accessor deliberately - a separate, pre-existing narrowing gap there means the bang variant would just relocate the same symptom one line down.

Test plan: Full-workspace solargraph typecheck --level strong before/after: message-text diff is byte-for-byte empty (531 problems both times) - 24 of the 39 targeted markers cleared plus 1 bonus, 0 new findings. Full spec suite: 1650 examples, 0 failures. New spec added: spec/range_spec.rb.

Range.from_node returns nil only when a node lacks real source
location info (a synthesized node). Every one of its 24 unguarded
call sites in this codebase passes a node freshly parsed from real
source (flow-sensitive-typing node processors, Source#node_at/
tree_at traversal, Pin::BaseVariable#assignment, Pin::Block#receiver,
dstr children), where that case cannot occur, so each carried a
"Need to add nil check here" suppression instead of a real guard.

Add a non-nilable Range.from_node! that raises instead, and switch
those call sites to it, removing their suppressions. One further
downstream suppression cleared as a side effect: with the resulting
Range non-nilable, Solargraph now resolves
Solargraph::TypeChecker#call_problems' Location.new(filename, rng)
correctly without its own nil-check marker.

One site (Source#inner_folding_ranges) keeps the nilable from_node
and its guard: the node passed there is separately unnarrowed after
an earlier is_ast_node? check, an unrelated existing gap, so
from_node! would still need a suppression there for a different
reason.
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