Fix and re-enable strong-level typechecking in CI - #1240
Conversation
Part of re-enabling `solargraph typecheck --level strong` in CI (currently `continue-on-error: true`, 496 pre-existing problems). - Remove 42 `@sg-ignore` comments strong-mode now reports as unneeded (the underlying issue they suppressed no longer exists). - lib/solargraph/source/chain/literal.rb: reword nested `@sg-ignore` mentions inside a commented-out illustrative code block so Solargraph's comment parser doesn't mistake them for live annotations (was causing a false "unneeded @sg-ignore" report with no matching live comment to remove). - lib/solargraph/yardoc.rb: keep one @sg-ignore in place (reworded) for an Open3.capture2e overload-resolution edge case strong mode can't otherwise clear; removing it surfaced a real "Unresolved call to success?" report. spec/pin/combine_with_spec.rb's 5 stale `pending` markers are intentionally NOT removed here: they only start passing once PR castwide#1238's Pin::Method#combine_same_type_arity_signatures fix is present, and that fix is being kept in a separate, non-annotation PR. Removing them on this branch (which doesn't have that fix) would turn 'pending' into a real failure. Verified: typecheck strong (497 -> 454 problems, no new problems introduced, no regressions). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit cb7bb61)
Continues re-enabling `solargraph typecheck --level strong` in CI. Root-cause fixes (not suppression): - lib/solargraph/rbs_translator.rb, lib/solargraph/rbs_map/conversions.rb: `RbsTranslator.to_complex_type`/`type_to_tag` were tagged `@param type [RBS::Types::Bases::Base]`, but RBS itself defines no such shared base type -- `RBS::Types::t` (RBS's own "any type" alias) is a flat union of ~20 concrete classes. Retagging both methods with that full union fixed 11 identical false-positive reports in one shot. Same fix applied to `RbsTranslator.to_parameter_pins` / `Conversions#extract_method_type_return_type`, which are genuinely called with either `RBS::MethodType` or `RBS::Types::Block` (both just need `.type`). - lib/solargraph/rbs_map/conversions.rb: removed two entirely dead, shadowed method definitions (`build_type`, `parts_of_function`) -- each had an earlier, unreachable definition still calling two methods (`method_type_to_type`, `other_type_to_type`) that don't exist anywhere in the codebase. Ruby silently uses the later definition, so this was always dead code, not a live bug, but it's why rubocop's Lint/DuplicateMethods was already flagging this file. - rooted_name/fqns/build_type: replaced `Hash#fetch(key, default)` (whose two-arg overload Solargraph can't resolve generically here) with `Hash#[] || default`, which type-checks correctly. - Real nil-safety fixes (guard rewritten so flow typing can see it, not suppressed): node_methods.rb's paren-scanning method-signature parser (String#[] with a Range is nilable even though the surrounding bounds checks make it unreachable in practice); location_decl_to_pin_location / RbsTranslator.to_sg_location's `location&.name.nil?` guards, rewritten as `location.nil? || location.name.nil?` so Solargraph narrows `location` afterward. Suppressions (matching this codebase's established @sg-ignore conventions, used where the gap is in Solargraph's own flow-typing engine, not a bug in this code -- see the categorized backlog in lib/solargraph/type_checker/rules.rb): - `Parser.is_ast_node?(x)`-style custom predicate wrappers don't narrow `x` for later calls (flow sensitive typing needs to narrow down type with an if is_a? check). - Postfix `unless x.nil?` guards on a repeated subexpression don't narrow the repeated use (Translate to something flow sensitive typing understands). - `if obj.attr` doesn't narrow a later `obj.attr` re-access (flow sensitive typing needs to handle attrs). - `case type; when SomeClass; type.foo` doesn't narrow `type` per branch (flow sensitive typing should support case/when). - A few pre-existing, unrelated-to-narrowing "Unresolved call" reports on RBS-derived types Solargraph can't otherwise resolve. spec/pin/method_spec.rb: switch the batch-1 regression test to `instance_double` (RSpec/VerifiedDoubles), fixing a rubocop failure CI caught on the batch-1 push. Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (454 -> 374 problems this batch; 497 -> 374 overall across both batches). Note: CI's `run_solargraph_rspec_specs` job (solargraph-rspec's own integration suite, run against this branch) shows 3 pre-existing failures. Confirmed via local bisection (pointing solargraph-rspec's Gemfile at a pristine, unmodified castwide/solargraph master checkout) that these same failures reproduce on master itself, and confirmed via `gh run list` that this job has already failed on a master push independent of this PR. Not caused by, or fixable within, this PR. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit e54709d)
Continues re-enabling `solargraph typecheck --level strong` in CI.
- lib/solargraph/type_checker.rb: fully clean (27 -> 0 problems).
Real fixes: `kwarg_problems_for` now returns early if
`sig.parameters[idx]` is nil (was calling `.name`/`.decl`/
`.asgn_code` on a possibly-nil param without a guard);
`arity_problems_for` now falls back to `[]` if
`pin.signatures.map { ... }.first` is nil (empty signatures list).
The rest are `@sg-ignore`s matching this codebase's established
flow-typing-gap conventions (postfix nil guards, attr re-access,
Hash `||=` on a key, `Array#last` after an emptiness check).
- lib/solargraph/rbs_translator.rb: wrap the two `@param type [...]`
union-type tags (added in batch 2) in
`rubocop:disable/enable Layout/LineLength` -- CI's rubocop check
caught these on the batch 2 push (511/513 chars vs the 224 limit).
Verified: full rspec suite (1618 examples, 0 failures, 60 pending)
and typecheck strong (374 -> 347 problems this batch; 497 -> 347
overall across three batches).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit d940789)
Continues re-enabling `solargraph typecheck --level strong` in CI. lib/solargraph/pin/method.rb: fully clean (17 -> 0 problems). Real fixes: - `return_type_from_inline_rbs` / `signatures_from_inline_rbs`: guard against `RBS::Parser.parse_method_type` returning `nil` (its own RBS signature allows this independent of raising `RBS::ParsingError`, which is the only failure mode these methods previously handled). - `dodgy_visibility_source?`: add a `@return [Boolean]` tag (was missing, same "return type could not be inferred" pattern already fixed for `splatted_hash?` in batch 2). The rest are `@sg-ignore`s matching this codebase's established flow-typing-gap conventions from lib/solargraph/type_checker/rules.rb (String#[] with a Range being nilable despite surrounding bounds checks, Array#first/#last after an emptiness check, attr re-access after a truthy check, Hash `||=` on a key). One (`Macro.from_directive` called with an already-built `Macro` instead of a raw `YARD::Tags::Directive`) works at runtime only because `Macro` duck-types `#tag` the same way -- confirmed by reading both classes before suppressing rather than assuming. Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (347 -> 330 problems this batch; 497 -> 330 overall across four batches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit 3262e75)
Continues re-enabling `solargraph typecheck --level strong` in CI. - lib/solargraph/parser/parser_gem/node_chainer.rb: fully clean (15 -> 0 problems). - lib/solargraph/parser/parser_gem/node_processors/send_node.rb: fully clean (17 -> 0 problems). Both files are almost entirely `node.children[N]` accesses feeding into recursive chain-building calls (`NodeChainer.chain`, `generate_links`) after guards Solargraph's flow typing doesn't propagate (`is_a?` checks, truthiness checks, or just structural guarantees from the parser's own AST shape) -- `@sg-ignore`s matching the established "Need to add nil check here" convention. One real (harmless) restructuring: `NodeChainer#generate_links`'s `:or` branch built a two-element array inline (`[NodeChainer.chain(n.children[0], ...), NodeChainer.chain(n.children[1], ...)]`), which put both nilable-argument call sites on the same logical statement -- Solargraph could only attribute one `@sg-ignore` to it. Split into two local variables assigned separately so each call site gets its own annotation; no behavior change. Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (330 -> 298 problems this batch; 497 -> 298 overall across five batches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit 3960c11)
…y clean Continues re-enabling `solargraph typecheck --level strong` in CI. - lib/solargraph/parser/comment_ripper.rb: fully clean (15 -> 0 problems). All from the same root: Ripper's `result` tuple is declared `Array(Symbol, String, Array(...))`, but Solargraph doesn't narrow positional `result[N]` indexing to each tuple slot's specific type -- every index resolves to the full element-type union instead. `@sg-ignore`s matching this file's existing convention for the identical pattern. - lib/solargraph/parser/flow_sensitive_typing.rb: fully clean (13 -> 0 problems). Same nil-narrowing gaps as prior batches (`@type` tags asserting non-nil on values Solargraph itself infers as nilable from `node.children[N]`; a nested generic Hash/Array value type Solargraph can't fully resolve). Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (298 -> 270 problems this batch; 497 -> 270 overall across six batches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit 319dea9)
Continues re-enabling `solargraph typecheck --level strong` in CI. lib/solargraph/library.rb: fully clean (12 -> 0 problems). Real fixes: - `references`: `[api_map.source_map(filename)]` could contain a nil element (source_map returns nil if the file isn't mapped); `.compact` it before iterating, avoiding a latent `NoMethodError` on `nil` if that branch were ever hit with an unmapped file. - `next_map`: was writing to and then immediately re-reading from `source_map_hash` to get its own return value, which Solargraph can't see is guaranteed present -- keep the mapped source in a local variable and return that instead of re-fetching from the hash. The rest are `@sg-ignore`s matching established conventions: the `nil`-literal-vs-`NilClass` representation mismatch also seen in batch 4 (`attach nil`, `Bench.new(live_map: ...)`), the `Open3.capture3` overload-resolution gap from batch 4 applied to a second call site, and a few more `Array#shift`/`Hash#[]`-after-a-set nil-narrowing gaps. Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (270 -> 258 problems this batch; 497 -> 258 overall across seven batches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit 4b62fd4)
Continues re-enabling `solargraph typecheck --level strong` in CI. - lib/solargraph/api_map.rb: fully clean (12 -> 0 problems). - lib/solargraph/language_server/host.rb: fully clean (12 -> 0 problems). Real fixes: - `Host#pending_completions?` was tagged `@return [Bool]` -- not a real YARD/Solargraph type name (should be `Boolean`), so the declared type itself was unresolvable. - `Host#client_supports_progress?` / `#prepare_rename?` had no `@return` tag at all and returned a raw `&&` chain (which could yield a Hash value, not just true/false); added `@return [Boolean]` and wrapped the body in `!!(...)` so the return value is a real boolean, not just type-annotated as one. The rest are `@sg-ignore`s matching established conventions: several more `Hash#[]`-after-a-truthy-check nil-narrowing gaps, the `nil`-literal-vs-`NilClass` mismatch (`Source::Change.new` with a ternary that can yield literal `nil`), and one gap in a third-party gem's return typing (`Diff::LCS.diff`, which doesn't ship strong RBS/YARD types Solargraph can resolve). Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (258 -> 234 problems this batch; 497 -> 234 overall across eight batches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit d0cb67a)
Continues re-enabling `solargraph typecheck --level strong` in CI.
lib/solargraph/api_map/store.rb: fully clean (10 -> 0 problems).
Real fixes:
- `get_path_pins`: `index.path_pin_hash[path]` falls back to `[]`
(matches the declared non-nilable `Array<Pin::Base>` return type;
Hash#[] on a missing key is a normal, expected case here, not an
error).
- `fqns_pins`: `fqns_pins_map[[base, name]]` falls back to `[]` too --
the hash has a default proc that always populates the key, so this
never actually returns nil, but Solargraph can't see through
`Hash.new { ... }` default-proc population.
The rest are `@sg-ignore`s matching established conventions:
`Hash#key?`-guard-then-`[]`-fetch not narrowing (same pattern fixed
repeatedly in prior batches, here across `superclass_references`,
`namespace_hash`, `@indexes.last`), and the `nil`-literal-vs-`NilClass`
representation mismatch in a cached Hash assignment expression.
Verified: full rspec suite (1618 examples, 0 failures, 60 pending)
and typecheck strong (234 -> 224 problems this batch; 497 -> 224
overall across nine batches).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 5e8f295)
Continues re-enabling `solargraph typecheck --level strong` in CI.
- lib/solargraph/pin/block.rb: fully clean (9 -> 0 problems).
- lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb:
fully clean (9 -> 0 problems).
- lib/solargraph/diagnostics/rubocop.rb: fully clean (9 -> 0
problems).
Real fix: `Block#destructure_yield_types`'s `parameters.map.with_index
{ ... }` (map called without a block, then chained through
`with_index`) return-typed as `Enumerator` instead of `Array` --
rewritten as the equivalent, more standard
`parameters.each_with_index.map { ... }`, which Solargraph resolves
correctly and matches the declared `Array<ComplexType>` return type.
The rest are `@sg-ignore`s matching established conventions:
`is_a?` checks combined with `&&` in an `if`/`elsif` chain not
narrowing the checked variable for later `.type`/`.children` calls in
sclass_node.rb (same class of gap as the plain single-condition case
fixed in earlier batches, just with more conditions in the same
`if`); repeated `Hash#[]`-chain nil-narrowing gaps parsing RuboCop's
JSON offense output in diagnostics/rubocop.rb.
Verified: full rspec suite (1618 examples, 0 failures, 60 pending)
and typecheck strong (224 -> 197 problems this batch; 497 -> 197
overall across ten batches).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 2a262cd)
Continues re-enabling `solargraph typecheck --level strong` in CI. - lib/solargraph/convention/data_definition/data_assignment_node.rb: fully clean (7 -> 0). - lib/solargraph/convention/struct_definition/struct_assignment_node.rb: fully clean (7 -> 0). - lib/solargraph/convention/struct_definition/struct_definition_node.rb: fully clean (7 -> 0). Real fix, applied identically across the two `*_assignment_node.rb` files (they're structurally the same class, one for `Data.define`, one for `Struct.new`): `node.children[2]` and `node.children[0]` were each re-evaluated 2-3 times across a nil check and subsequent uses. Solargraph doesn't narrow a repeated method-call expression the way it narrows a plain local variable, so each re-access re-triggered the same nilable warning even though the code was already guarded. Extracting each into a local variable once, right after computing it, lets Solargraph's ordinary local-variable nil-narrowing do its job instead of suppressing each repeated access individually. The remaining occurrences (mostly in `struct_node`/`data_node` private helper methods that intentionally re-derive from `node` without a preceding nil check, and a few multi-level `.children[0]` chains) are `@sg-ignore`s matching this codebase's established conventions. Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (197 -> 176 problems this batch; 497 -> 176 overall across eleven batches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit e51fe1f)
Continues re-enabling `solargraph typecheck --level strong` in CI. - lib/solargraph/doc_map.rb: fully clean (8 -> 0 problems). - lib/solargraph/pin/callable.rb: fully clean (7 -> 0 problems). - lib/solargraph/source.rb: fully clean (7 -> 0 problems). All `@sg-ignore`s matching this codebase's established conventions from earlier batches: `Hash#key?`-guard/`Hash#[]=`-then-fetch not narrowing, the `Open3.capture3` overload-resolution gap (a third call site, same as batches 4 and 7), `||=` on a Hash key not narrowing, and the `nil`-literal-vs-`NilClass` representation mismatch. One case in `source.rb` also carries a real type-hierarchy gap Solargraph can't see: `Parser::AST::Node` is a subclass of the `ast` gem's `AST::Node`, but nothing tells Solargraph about that relationship, so a method declared to return `AST::Node` that actually returns a `Parser::AST::Node, nil` needs suppressing on both counts. Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (176 -> 154 problems this batch; 497 -> 154 overall across twelve batches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit 287fff7)
Continues re-enabling `solargraph typecheck --level strong` in CI.
- lib/solargraph/complex_type.rb: fully clean (7 -> 0 problems).
- lib/solargraph/complex_type/unique_type.rb: fully clean (7 -> 0
problems).
Real fix: `ComplexType#expand` and `UniqueType#expand` had no
`@param`/`@return` tags at all; added `@param named_types
[Hash{String => UniqueType}]` / `@return` tags matching how they're
actually used (`named_types[name] || self`).
The rest are `@sg-ignore`s matching established conventions:
`Array#first`/`Array#[]` on `@items` treated as guaranteed-present
(a ComplexType always wraps at least one UniqueType) but not
provable statically, and the `nil`-literal-vs-`NilClass`
representation mismatch.
Verified: full rspec suite (1618 examples, 0 failures, 60 pending)
and typecheck strong (154 -> 140 problems this batch; 497 -> 140
overall across thirteen batches).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 246d72b)
Continues re-enabling `solargraph typecheck --level strong` in CI. - lib/solargraph/pin_cache.rb: fully clean (6 -> 0 problems). - lib/solargraph/pin/base.rb: fully clean (6 -> 0 problems). - lib/solargraph/yard_map/mapper/to_method.rb: fully clean (6 -> 0 problems). - lib/solargraph/shell.rb: fully clean (6 -> 0 problems). Real fixes: `Pin::Base#macro_names` and `#collect_macro_names` had no `@return` tag at all; added `@return [Array<String>]` matching their actual behavior. `Shell#rbs` (a Thor CLI command) had no `@return` tag either; added `@return [void]`. The rest are `@sg-ignore`s matching established conventions, including a new instance of the `FileUtils::path` RBS type-alias gap (6 call sites across pin_cache.rb and shell.rb -- `FileUtils::path` is an RBS type alias for a String/Pathname union, but Solargraph doesn't resolve the alias against a literal String argument) and the `choose_pin_attr_with_same_name` dynamic-`send`-based generic return gap already seen for its sibling `choose_pin_attr` in batch 12. Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (140 -> 117 problems this batch; 497 -> 117 overall across fourteen batches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit 5f63ed2)
…specs Continues re-enabling `solargraph typecheck --level strong` in CI. - lib/solargraph/api_map/cache.rb: fully clean (5 -> 0). - lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb: fully clean (5 -> 0). - lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb: fully clean (5 -> 0). - lib/solargraph/source_map/clip.rb: fully clean (5 -> 0). - lib/solargraph/workspace/gemspecs.rb: fully clean (5 -> 0). Real fixes: - `Cache#get_methods`/`#get_constants`/`#get_receiver_definition` are Hash-backed cache lookups that can genuinely miss (declared non-nilable but a `Hash#[]` cache read can return nil) -- widened their `@return` tags to include `nil`, matching how their one caller (`ApiMap#get_methods`, `unless cached.nil?`) already treats them. - `NamespaceNode#parameters_from_inline_rbs`: replaced a guard-then-repeated-access on `match[1]` with a local variable so Solargraph's ordinary nil-narrowing applies. - `ResbodyNode#process`: same fix for `node.children[1]`, reused across four lines in the method. - `Workspace::Gemspecs#gemspec_or_preference`: same `preference_map` `Hash#key?`-guard pattern already fixed in `DocMap` (batch 12) -- this is a separate, similarly-named method in a different class. The rest are `@sg-ignore`s matching established conventions, including a fourth `Open3.capture3` overload-resolution gap site. Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (117 -> 92 problems this batch; 497 -> 92 overall across fifteen batches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit c1e5db8)
… nodes Continues re-enabling `solargraph typecheck --level strong` in CI. Note: this branch's original base already called simple_resolve(name, mixin, internal) in Constants#complex_resolve's mixin-recursion branch (a pre-existing bug: simple_resolve only resolves one gate, unlike resolve(name, mixin), which recurses through resolve_and_cache across all of mixin's own ancestry, so multi-hop transitive constant resolution silently broke -- e.g. Module4 includes Module3 includes Module2 includes Module1, with a constant assigned in Module2 referenced from Module4). castwide/master fixed this independently in castwide#1234 ('resolves remote constants'), which also added a regression test for it, after this branch was created. Since this consolidation branch is built on current master, that fix is already present; keeping master's resolve(name, mixin) as-is here rather than reintroducing the stale simple_resolve call via this cherry-pick's patch context. Kept the rest of this commit's sg-ignore comments and annotation fixes elsewhere in this file/batch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit 035705ca4d2d7f00c5a67e0c9a24f81f14fa789e)
…, ParseDirective Continues re-enabling `solargraph typecheck --level strong` in CI. - lib/solargraph/parser/node_processor.rb: fully clean (3 -> 0). - lib/solargraph/parser/parser_gem/node_processors/args_node.rb: fully clean (3 -> 0). - lib/solargraph/source/chain.rb: fully clean (3 -> 0). - lib/solargraph/source_map.rb: fully clean (3 -> 0). - lib/solargraph/yard_map/directives/parse_directive.rb: fully clean (3 -> 0). All `@sg-ignore`s matching established conventions from earlier batches: `||=` on a class variable Hash not narrowing, `Array#last` treated as guaranteed-present, generic-method (`_locate_pin`) downcasts to specific return types, and the `nil`-literal-vs-`NilClass` ternary mismatch. Verified: full rspec suite (1618 examples, 0 failures, 60 pending) and typecheck strong (72 -> 57 problems this batch; 497 -> 57 overall across seventeen batches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit 6d0b3ad)
…e hard-fail
Closes the last 41 problems, bringing `solargraph typecheck --level
strong` from 497 problems (when this PR started, method stubbed) to
0. Also removes `continue-on-error: true` from the typecheck CI step
(the `@todo Temporary, expect to revert in 0.60` this PR has been
working toward since batch 1) -- strong mode is now a real, enforced
gate again, not just informational.
18 files hit real fixes:
- `Workspace#source` / `#synchronize!`, `YardMap::Cache#get_path_pins`,
`YardMap::Mapper#macros_for_method_object`: Hash-backed lookups
declared non-nilable but genuinely can miss -- widened return types
or added `|| []`/`|| default` fallbacks matching how callers
already treat them.
- `Host::Message.select`, three `set_result nil` call sites,
`RbsMap#short_name`, `Source::Chain::Literal#value`: missing or
wrong `@return`/`@param` tags (a literal `[Bool]` typo, an
`attr_reader` with no declared type at all).
- Five identical `closure_at` methods across
yard_map/directives/{attribute,domain,method,override,visibility}_directive.rb
shared the exact same `Array#select.last` pattern already root-caused
and fixed once for parse_directive.rb in batch 17.
The remaining ~30 files are `@sg-ignore`s matching every convention
established across this PR's 18 batches: `Hash#[]`/`Array#last`
guard-then-fetch not narrowing, the `nil`-literal-vs-`NilClass`
mismatch, the `Open3.capture3` overload-resolution gap (two more
sites), and the `FileUtils::path` RBS type-alias gap (now also fixed
in this repo's own Rakefile, which the strong-mode target apparently
covers too).
Verified: full rspec suite (1618 examples, 0 failures, 60 pending)
and typecheck strong: 41 -> 0 problems in 250 files, exit code 0.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 1ecdfc7)
…-room verification `Gem::StubSpecification` was unresolvable as a constant in a freshly bundled, freshly `rbs collection install`-ed environment (Docker ruby:4.0, matching the CI recipe exactly), even though this repo's long-lived local development bundle didn't hit it -- this repo has no committed Gemfile.lock or rbs_collection.lock.yaml (both gitignored), so every fresh install resolves whatever gem/RBS versions are current at that moment. `@sg-ignore` matching this PR's established pattern for RBS-resolution gaps in `case`/`when`. Caught by re-verifying the final batch in a brand-new Docker container + fresh clone, rather than trusting the long-lived local bundle this whole PR was developed against -- worth flagging as a real (if narrow) source of CI flakiness independent of any code change here, since a *different* constant could equally fail to resolve on a different day depending on what gem_rbs_collection's `main` branch or RubyGems' own RBS core sigs look like at that moment. Verified in a fresh Docker clean-room (bundle install + rbs collection install from scratch, matching CI): typecheck strong 0 problems, exit 0. Full rspec suite: 1618 examples, 0 failures, 60 pending. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit 6a4961f)
CI (Solargraph / strong, hard-fail since batch 18) found 4 problems against current castwide/master that did not exist when this branch was originally authored: - lib/solargraph/api_map/constants.rb:162: batch 16's cherry-pick context assumed the old simple_resolve(name, mixin, internal) call this branch's base had; since this branch keeps master's corrected resolve(name, mixin) (see batch 16's message), the @sg-ignore that used to suppress an 'Unresolved call to +' on the idx + 1 access a few lines down (closure-captured from the outer with_index block) got dropped along with it. Restored it in its new spot. - lib/solargraph/doc_map.rb:427, workspace/gemspecs.rb:213, workspace/require_paths.rb:84: three @sg-ignore comments that predate this branch (none of the 19 batches touch these lines) are now flagged unneeded -- upstream master's type inference improved enough since this branch was created that they're no longer required. Removed. Verified: full rspec suite (1618 examples, only the 2 pre-existing environment-dependent shell_spec.rb failures also present on castwide/master), rubocop (no new offenses vs. baseline). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Let's separate code changes into a separate PR and reference the PR # in @sg-ignore comments so we can keep this one annotation-only |
The 28 non-comment hunks that touched actual Ruby behavior (nil-guard fixes, return-value corrections, dead duplicate method removal, Sorbet-narrowing refactors) now live in castwide#1245. This branch reverts those hunks back to their pre-cleanup form and marks each resulting strong-typecheck gap with an @sg-ignore comment referencing castwide#1245, so this PR stays annotation- and CI-gate-only as requested. Verified via solargraph typecheck --level strong: normalized diff against the pre-revert state of this branch shows zero net-new problems introduced by the revert (all reverted spots are covered by the new ignores; remaining diffs are pre-existing version-drift noise already present on this branch). Full test suite: 1618 examples, 0 failures. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYQc4tRAkDEfp6vZsvHaXr
|
Done. Split the actual behavior-touching hunks out into #1245 (nil-guard fixes, return-value corrections, a dead duplicate-method removal in rbs_map/conversions.rb, and Sorbet-narrowing local-variable refactors) — see that PR for the full breakdown and test results. This branch now reverts those 28 hunks back to their pre-cleanup form and marks each resulting strong-typecheck gap with an @sg-ignore comment referencing #1245, so it's annotation- and CI-gate-only as requested. Verified via solargraph typecheck --level strong that the revert introduces zero net-new problems (normalized diff against the pre-revert state), and the full test suite still passes (1618 examples, 0 failures). —Claude |
The comment block above require_all_unique_types_match_expected? was a stale, hand-maintained tally of @sg-ignore reasons and counts. Recomputed from a full grep over lib/**/*.rb: 745 total (was ~373), reflecting both growth in the underlying campaign (e.g. "Need to add nil check here" 281 -> 465) and the new castwide#1245-deferred entries from this PR's split (29 nil-check, 13 downcast, 6 return-value, 3 dead-code-removal). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYQc4tRAkDEfp6vZsvHaXr
PR castwide#1201 disabled tuple/literal element-type inference wholesale to fix specious-inference reports (castwide#1196). That's the root cause of a broad swath of downstream nil-check/downcast/overload-resolution gaps across the codebase, not just tuple indexing. Open PR castwide#1223 restores the capability properly (with real reassignment tracking) rather than leaving it off. Determined the exact set empirically: test-merged castwide#1223's branch onto this one and diffed `solargraph typecheck --level strong` output before/after (line numbers stripped to avoid false positives from line-count shifts). Every one of the 79 lines flagged "Unneeded @sg-ignore comment" in that diff had its comment rewritten to `# @sg-ignore https://github.com/castwide/solargraph/pull/1223`, replacing whatever specific reason (or blank comment) was there before - including one of this branch's own castwide#1245-deferred entries (pin/block.rb), which turns out to be downstream of the same root cause. Updated the @sg-ignore count doc in TypeChecker::Rules to add this as a third bucket and adjust the other two accordingly. Verified: full test suite (1618 examples, 0 failures) and `solargraph typecheck --level strong` both unchanged from before this commit (comment-only diff, confirmed via normalized before/after output comparison). Rubocop offenses on touched files identical before and after (36, all pre-existing). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYQc4tRAkDEfp6vZsvHaXr
Writing out '@sg-ignore' in prose (not as a real directive) made Solargraph's ignore-scanner treat it as one, flagging require_all_unique_types_match_expected? with a spurious Unneeded @sg-ignore comment warning. Switched to '@ sg-ignore' (space), matching the existing convention already used a few lines below in this same file. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYQc4tRAkDEfp6vZsvHaXr
|
Investigated whether the sg-ignore count growth (373 → 745 in my last update) reflects a regression rather than organic accumulation. Found one: PR #1201 ("Ignore literal values in type inference," merged 2026-05-21) disabled tuple/literal element-type inference wholesale to fix specious-inference reports (#1196). Open PR #1223 restores it properly. That disabling turns out to be the root cause of a broad swath of downstream nil-check/downcast/overload-resolution gaps (e.g. Determined the exact affected set empirically rather than guessing by category name: test-merged #1223's branch on top of this one and diffed Updated the count doc in —Claude |
Collapse the four different castwide#1245-deferred reason strings (nil-check, downcast, return-value, dead-code-removal) down to one consistent `# @sg-ignore https://github.com/castwide/solargraph/pull/1245`, matching the castwide#1223 reference style and the repo's existing convention of pointing an ignore straight at the PR that resolves it rather than re-describing the reason inline. Reverted the count doc in TypeChecker::Rules to the original flat two-bucket format (no prose commentary) and regenerated the counts using the actual ~/bin/solargraph-errors-group tool per the documented recipe in ~/Dropbox/Shared/solargraph.md, rather than an ad-hoc filter. The castwide#1223 and castwide#1245 buckets are now single flat count lines in "pending code fixes," not broken out by what they used to be. Verified: full test suite (1618 examples, 0 failures), rubocop clean, and `solargraph typecheck --level strong` stable at 72 problems (unchanged from before this commit). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYQc4tRAkDEfp6vZsvHaXr
The 28 "flow sensitive typing should support case/when" / "flow based typing needs to understand case when class pattern" ignores in rbs_translator.rb and rbs_map/conversions.rb all describe the same gap: the type checker doesn't narrow a case/when subject's type inside each branch. Filed and confirmed as castwide#1241 - rewrote all 28 to point there instead of restating the reason inline, matching the castwide#1223/castwide#1245 convention. Checked for issue coverage on the other "flow sensitive typing could handle" categories too (attrs, redefinition, ||= on lvars, .class == .class, boolish support, etc.) - no clear existing issue found for those via search, so left as-is. Also checked "Need to handle duck-typed method calls on union types": issues castwide#453/castwide#511 looked like a match at first glance but describe a different mechanism (YARD `@return [#call]` duck-type tags, not union-type method resolution) so left unlinked rather than mis-attribute it. Regenerated the count doc using solargraph-errors-group per the documented recipe. Verified via a clean stash/restore comparison (not just before/after diffing, since consecutive typecheck runs have shown transient non-determinism this session) that this comment-only change introduces zero new problems: full test suite 1618 examples/0 failures, rubocop clean, typecheck stable at 72. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYQc4tRAkDEfp6vZsvHaXr
Three of the largest remaining "flow sensitive typing could handle" categories described coherent, reproducible gaps with no existing tracking issue (searched castwide/solargraph issues first, no match): - "flow sensitive typing needs to handle attrs" (30): a nil-guard on an attr_reader-style call doesn't narrow a later repeated call to the same accessor, since each call is treated as independent rather than as if it were a local variable. Filed as castwide#1249. - "flow sensitive typing should be able to handle redefinition" (20): reassigning a variable to a value of a different (non-literal) type doesn't update its tracked type - distinct from castwide#1196/castwide#1223, which cover literal-value tracking through reassignment specifically for array/tuple indexing. Filed as castwide#1250. - "flow sensitive typing needs to narrow down type with an if is_a? check" (12): narrower-scoped than castwide#1241 (case/when) - covers is_a? checks combined with && and elsif branches whose body doesn't see the narrowing established by its own condition. Filed as castwide#1251. Rewrote all matching @sg-ignore comments to point at the new issues, matching the castwide#1223/castwide#1245/castwide#1241 convention. Left the 4 sg-ignore notes inside the disabled block in source/chain/literal.rb untouched (not live directives) and the standalone @todo in shell.rb (different tag, outside this doc's scope). Regenerated the count doc via solargraph-errors-group. Verified: full test suite (1618 examples, 0 failures), rubocop clean on all touched files, and solargraph typecheck --level strong stable at 72 (checked against a pre-edit baseline captured via stash, given transient non-determinism observed between consecutive runs this session). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYQc4tRAkDEfp6vZsvHaXr
CI's strong-typecheck job flagged one problem this PR introduced: reverting the found_versions extraction (deferred to castwide#1245) earlier this session dropped the @sg-ignore Need a downcast here comment that covered it, since CI's fresh gem install resolves Gem::Version differently than my local (stale) gem cache did. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYQc4tRAkDEfp6vZsvHaXr
The ignore only associated with the raise statement's first line, not the string-continuation line where the actual problem is reported. Placing a comment between backslash-continued string literals silently drops the second string at runtime (verified) rather than erroring, so switched to + concatenation, which tolerates a comment between the operands without changing behavior (verified the raised message is byte-identical to before). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYQc4tRAkDEfp6vZsvHaXr
|
@castwide - ready for review |
…notation-cleanup # Conflicts: # lib/solargraph/rbs_map/conversions.rb # lib/solargraph/source.rb
…collection environment Annotation-only: @sg-ignore comments and a few doc-type corrections (Set vs Array, Thread::Mutex vs Mutex, Pin::Symbol vs ::Symbol namespace collisions) for pre-existing gaps in already-annotated files that this PR's local Ruby 3.2.6 testing didn't surface.
… Ruby patch CI runs Ruby 4.0.6; my local verification used rbenv's 4.0.0, where this constant resolved and the ignore looked unneeded. CI disagreed -- trusting CI per this repo's convention for local/CI typecheck disagreements.
lib/solargraph/source/chain/literal.rb: attr_reader :word, :value stays on one line as originally written; annotate the whole line with @sg-ignore rather than splitting it to give :value its own @return tag.
Re-enables `solargraph typecheck --level strong` as an enforced CI gate - removes `continue-on-error: true` from .github/workflows/typecheck.yml. Most of the diff is @sg-ignore comments documenting type gaps strong mode can't resolve on its own (flow-sensitive-typing limits, the nil-vs-NilClass representation mismatch, guard-then-fetch patterns that don't narrow, RBS overload/ type-alias gaps). A handful of real fixes are included (missing/wrong @return/@PARAM tags). This branch's own lib/ tree has diverged substantially from castwide#1240's target (39+ merged PRs' worth of independent work), so merging this required a full annotation sweep on top of the mechanical merge to actually make the newly-hard CI gate pass - see below. Conflicts (20 files) fell into two categories: 1. Genuine competing logic, where incoming's branch (based directly on castwide/master) predated work already merged into this branch. Kept this branch's side throughout: doc_map.rb's entire in-memory pin-cache architecture (superseded by the PinCache instance-based rewrite from castwide#1252, same pattern already identified during the castwide#1239 investigation earlier this session), rbs_translator.rb's compound-type-as-ComplexType-graph architecture (from castwide#1281, predates incoming's tag-string type_to_tag reintroduction), flow-sensitive-typing/node_chainer additions (rhs_never_returns tracking from castwide#1259), base_variable.rb's definite/narrowed_return_type naming (from castwide#1282), node_methods.rb's ENSURE handling (from castwide#1285), chain.rb/call.rb's receiver_path threading, and workspace.rb/pin_cache.rb duplicate method definitions incoming reintroduced that already exist elsewhere in this branch's own `class << self` blocks. 2. Pure annotation differences (add/adjust an @sg-ignore comment) where kept whichever side matched this branch's actual code structure. 2. Annotation sweep: after resolving conflicts, this branch's strong typecheck still reported 289 problems (down from 547 pre-merge, since castwide#1240's own annotations covered about half). 194 were "Unneeded @sg-ignore comment" (incoming's own ignore comments, correct on castwide#1240's target tree, landing on lines this branch's independent fixes already resolve) - removed mechanically by scanning upward from each flagged line for its comment. The remaining 95 were genuine new gaps on this branch's own code paths (mostly not exercised by castwide#1240's target tree at all) - added one @sg-ignore per flagged line, matching the established message-as-comment convention used throughout this codebase (@sg-ignore matches by string presence, not exact message, so one comment per line suffices even where a line has multiple flagged sub-expressions). Spot-checked the ones that looked most like real bugs rather than static-analysis gaps (BigDecimal-typed values in Integer-declared contexts, an Array#push type mismatch) against already-documented, already-tracked false-positive patterns in this codebase (the known BigDecimal-contamination artifact from earlier PR work, and a known is_a?-narrowing gap) - none were new bugs. Also fixed one new Style/Next rubocop offense the sweep introduced. Verified: full local `bundle exec rspec` (1826 examples, 0 failures, 51 pending - the only local-environment-dependent example, 'ignores undefined method calls from external sources', a pre-existing order-dependent kramdown-parser-gfm gem-cache flake already confirmed unrelated to this session's work, passed in this run), `solargraph typecheck --level strong` (0 problems, confirming the now-hard-gated CI job will pass), and `rubocop lib/` (13 offenses, matching this branch's pre-existing baseline exactly - none newly introduced by this merge).
#49 CI (commit c53789b) failed two checks after castwide#1240 turned Solargraph/strong from advisory into a hard gate: - Solargraph/strong: this job runs Ruby 4.0 with the `vernier` gem installed (appended to .Gemfile in the workflow itself) and a freshly-installed RBS collection, none of which match this session's local verification environment (Ruby 3.2.6, no vernier). Three `# @sg-ignore Unresolved constant Vernier` comments in shell.rb and one `# @sg-ignore Declared return type ::Integer does not match inferred type ::BigDecimal` in source_chainer.rb (the known BigDecimal-contamination artifact from earlier PR work) were "Unneeded" there since Vernier resolves and the BigDecimal gap doesn't reproduce on Ruby 4.0 - removed. A new gap CI's fresh RBS install surfaces that this session's local environment didn't - `Unresolved constant Gem::StubSpecification` in workspace/gemspecs.rb - added. Since this job runs a single fixed Ruby/RBS combination (not a matrix) and is now the actual enforced gate, resolved these in favor of matching CI's environment exactly rather than this session's local one - local `solargraph typecheck --level strong` now shows the mirror-image gaps (Vernier unresolved x3, BigDecimal x1, since local lacks vernier and has the BigDecimal artifact), which is expected and matches this project's established pattern for environment-dependent typecheck gaps. - rubocop (reviewdog, filter_mode: added): flags any rubocop offense falling within the diff's changed hunks, not just genuinely new ones. Removing the 3 Vernier ignore-comment lines from inside Shell#profile touched that method's hunk, pulling its pre-existing (already at 110.1/110 before this session touched it) Metrics/AbcSize offense into scope. Added lib/solargraph/shell.rb to .rubocop_todo.yml's existing Metrics/AbcSize exclusion list, matching the pattern already used for api_map/source_to_yard.rb/node_chainer.rb/source_chainer.rb/clip.rb/ mapper.rb. Verified: spec/shell_spec.rb, spec/source/source_chainer_spec.rb, spec/workspace/gemspecs_resolve_require_spec.rb, spec/workspace/gemspecs_fetch_dependencies_spec.rb (87 examples, 0 failures), and `rubocop lib/solargraph/shell.rb` (0 offenses, previously 1).
… stub A class defined in a gem and re-opened elsewhere via @!parse to add @Generic tags produced two pins for the same namespace/method path. ApiMap picked whichever pin loaded first - a gem's own pins load before workspace pins, so the annotation's @Generic declaration and overridden return types were silently ignored regardless of file naming/order. - ApiMap#namespace_pin_for_generics prefers the pin that actually declares generics over an arbitrary .first, used at the three call sites that resolve generic type parameters (get_methods, inner_get_methods, inner_get_methods_from_reference). - ApiMap::Store#get_methods combines same-path method pins into one, so a @!parse override's return type isn't shadowed by the plain, undocumented definition. Aliases are excluded from this combination: combining a MethodAlias pin with a non-alias pin at the same path produced a :combined pin that #resolve_method_alias couldn't trace back to its target, raising under SOLARGRAPH_ASSERTS=on. Fixes castwide#1286 Conflict in spec/source_map/clip_spec.rb: both sides independently added a new spec adjacent to the same insertion point - no real overlap, kept both. Verified: spec/source_map/clip_spec.rb, spec/api_map/store_spec.rb, spec/api_map_spec.rb, spec/api_map_method_spec.rb (284 examples, 0 failures, 11 pending), SOLARGRAPH_ASSERTS=on solargraph typecheck --level strong (4 problems, all in lib/solargraph/shell.rb and lib/solargraph/workspace/gemspecs.rb - the same Vernier-gem/ Gem::StubSpecification local-vs-CI environment split already established during the castwide#1240 merge, not new here), and a broader safety net - spec/type_checker, spec/source, spec/pin (612 examples, 0 failures, 18 pending).
…wide#1281 fix #49 CI (commit a6942fc, merge of latest castwide#1281 - resolve type alias names against RBS core) failed Solargraph/strong: 9 "Unneeded @sg-ignore comment" problems, all wrapping FileUtils.rm_rf/rm_f/mkdir_p calls in Rakefile, lib/solargraph/pin_cache.rb, and lib/solargraph/shell.rb. Each ignore was covering "Wrong argument type for FileUtils.*: list expected FileUtils::path, ..., received String" - exactly the FileUtils::path alias-resolution gap the just-merged fix closes, so on CI's Ruby 4.0 + fresh RBS collection environment these calls now typecheck cleanly without the ignore. Confirmed genuinely environment-dependent, not a stale local cache: cleared ~/.cache/solargraph/ruby-3.2.6/rbs-4.1.2/solargraph-* and reran - 4 of the 9 removed comments (3 in pin_cache.rb, 1 in shell.rb) are still needed on this local environment (Ruby 3.2.6, RBS 4.1.2). Matches the same Ruby/RBS-version-dependent FileUtils::path resolution pattern already established for the Vernier-gem and Gem::StubSpecification gaps during the castwide#1240 merge - kept the removal as-is to match CI (the actual enforced gate) rather than restoring for local parity. Verified: spec/pin_cache_spec.rb, spec/shell_spec.rb (44 examples, 0 failures), and `rubocop lib/solargraph/pin_cache.rb lib/solargraph/shell.rb Rakefile` (0 offenses).
Re-enables
solargraph typecheck --level strongas an enforced CI gate — removescontinue-on-error: trueand the@todo Temporary, expect to revert in 0.60marker.Most of the diff is
@sg-ignorecomments documenting type gaps strong mode can't resolve on its own: flow-sensitive-typing limits (postfix nil guards,is_a?narrowing across branches, reassignment tracking), thenil-vs-NilClassrepresentation mismatch, guard-then-fetch patterns onHash#[]/Array#first/#lastthat don't narrow, and a few RBS overload/type-alias gaps.A handful of real fixes are included (missing/wrong
@return/@paramtags — e.g.Host#pending_completions?was tagged the nonexistentBool). Genuine nil-safety and return-value fixes are deferred to #1245 and marked here with@sg-ignore ... pending in #1245, keeping this PR annotation- and CI-gate-only.Test plan
bundle exec rspec: 1618 examples, 0 failuresSOLARGRAPH_ASSERTS=on bundle exec solargraph typecheck --level strong: only the gaps explicitly deferred to Fix nil-safety, return-value, and dead-code bugs across parser/type-checker/RBS layers #1245 remain — verified via before/after diff that the revert introduced no other new problems🤖 Generated with Claude Code