Summary
When a local variable or parameter is reassigned to the result of a call that narrows or changes its type (e.g. a Position, Array(Integer, Integer) union normalized down to just Position), the type checker keeps using the original declared/inferred type for later uses of that variable instead of the type of the value it was just reassigned to.
This is distinct from #1196/#1223 (which covers literal-value tracking through reassignment for array/tuple indexing) — this is about the checker not picking up a plain reassignment's new static type at all, for non-literal types.
Repro
# typecheck --level strong
class Position
# @return [Integer]
def line; end
end
module PositionNormalizer
# @param position [Position, Array(Integer, Integer)]
# @return [Position]
def self.normalize(position); end
end
# @param position [Position, Array(Integer, Integer)]
def describe(position)
position = PositionNormalizer.normalize(position)
# `position` is still typed as `Position, Array(Integer, Integer)`
# here, even though it was just reassigned to the return value of
# `normalize`, which is declared `@return [Position]`. `Array` has
# no `#line` method, so this is flagged as unresolved.
position.line
end
Context
Found while auditing @sg-ignore accumulation in #1240 (strong-level typecheck cleanup) — 20 occurrences across source.rb, api_map.rb, range.rb, shell.rb, type_checker.rb, pin/parameter.rb, and others. Representative real example (lib/solargraph/range.rb):
# @param position [Position, Array(Integer, Integer)]
# @return [Boolean]
def contain? position
position = Position.normalize(position)
# @sg-ignore flow sensitive typing should be able to handle redefinition
return false if position.line < start.line || position.line > ending.line
...
and (lib/solargraph/api_map.rb):
# @sg-ignore flow-sensitive typing should be able to handle redefinition
return false if sup.literal? && sub.literal? && sup.to_s != sub.to_s
sup = sup.simplify_literals.to_s
# @sg-ignore flow sensitive typing should be able to handle redefinition
sub = sub.simplify_literals.to_s
return true if sup == sub
Here sup/sub are reassigned from ComplexType/UniqueType to String via .to_s, but the checker keeps treating them as their pre-reassignment type afterward.
Summary
When a local variable or parameter is reassigned to the result of a call that narrows or changes its type (e.g. a
Position, Array(Integer, Integer)union normalized down to justPosition), the type checker keeps using the original declared/inferred type for later uses of that variable instead of the type of the value it was just reassigned to.This is distinct from #1196/#1223 (which covers literal-value tracking through reassignment for array/tuple indexing) — this is about the checker not picking up a plain reassignment's new static type at all, for non-literal types.
Repro
Context
Found while auditing
@sg-ignoreaccumulation in #1240 (strong-level typecheck cleanup) — 20 occurrences acrosssource.rb,api_map.rb,range.rb,shell.rb,type_checker.rb,pin/parameter.rb, and others. Representative real example (lib/solargraph/range.rb):and (
lib/solargraph/api_map.rb):Here
sup/subare reassigned fromComplexType/UniqueTypetoStringvia.to_s, but the checker keeps treating them as their pre-reassignment type afterward.