@!override with @overload doesn't dispatch per call site -- it applies only the first overload's signature to every call, unlike an identical @overload block on a real def
Issue drafted by Claude (Anthropic), filed on behalf of @apiology.
Summary
A method with multiple @overload tags on its own def dispatches
correctly per call site (the matching overload's param/return types
apply). The identical @overload block applied via @!override to an
existing method pin does not -- every call site gets the first
overload's signature, regardless of which overload actually matches the
arguments, including a false-positive argument-type rejection when a
later call's arguments only match a later overload.
Reproduction
module Passthrough
extend self
# @overload identity(arguments)
# @param arguments [Array<Hash>]
# @return [Array<Hash>]
# @overload identity(arguments)
# @param arguments [Array<String>]
# @return [Array<String>]
def identity(arguments)
arguments
end
end
# @param [Hash] hash
# @return [Hash]
def wrap_hash(hash)
Passthrough.identity([hash])[0]
end
# @param [String] str
# @return [String]
def wrap_str(str)
Passthrough.identity([str])[0]
end
solargraph typecheck --level strong on this: 0 problems -- both
wrap_hash and wrap_str resolve against the correct overload.
Now the same @overload block, moved off the def and onto an
@!override targeting an otherwise-plain method:
module Passthrough
extend self
def identity(arguments)
arguments
end
end
# @!override Passthrough#identity
# @overload identity(arguments)
# @param arguments [Array<Hash>]
# @return [Array<Hash>]
# @overload identity(arguments)
# @param arguments [Array<String>]
# @return [Array<String>]
# @param [Hash] hash
# @return [Hash]
def wrap_hash(hash)
Passthrough.identity([hash])[0]
end
# @param [String] str
# @return [String]
def wrap_str(str)
Passthrough.identity([str])[0]
end
Actual
Passthrough#identity return type could not be inferred
Declared return type ::String does not match inferred type ::Hash, nil for #wrap_str
Wrong argument type for Passthrough#identity: arguments expected Array<Hash>, received Array<String>
wrap_hash (matches overload #1) resolves fine. wrap_str (needs
overload #2) instead gets overload #1's Array<Hash> param type and
Array<Hash> return type forced onto it -- a genuine false positive,
since Array<String> is valid input per the second overload.
Expected
@!override-attached @overloads dispatch per call site identically to
@overloads on a real def -- the two reproductions above should
produce the same (clean) result.
Impact
This blocks using @!override/config/annotations_*.rb-style local
stubs to give multiple, argument-dependent signatures to third-party gem
methods whose source can't be edited directly -- exactly the case
@!override exists for. A single generic (@generic T) signature is
also not always sufficient (e.g. when a method's return type genuinely
differs by argument category, not just by a uniform type parameter), so
@overload is the only way to express that -- and it's broken
specifically in the one context (@!override) where it's needed most.
Environment
- solargraph 0.60.3 (apiology/solargraph fork, branch
2026-08-04, revision 71f16f832d6e)
@!overridewith@overloaddoesn't dispatch per call site -- it applies only the first overload's signature to every call, unlike an identical@overloadblock on a realdefIssue drafted by Claude (Anthropic), filed on behalf of @apiology.
Summary
A method with multiple
@overloadtags on its owndefdispatchescorrectly per call site (the matching overload's param/return types
apply). The identical
@overloadblock applied via@!overrideto anexisting method pin does not -- every call site gets the first
overload's signature, regardless of which overload actually matches the
arguments, including a false-positive argument-type rejection when a
later call's arguments only match a later overload.
Reproduction
solargraph typecheck --level strongon this: 0 problems -- bothwrap_hashandwrap_strresolve against the correct overload.Now the same
@overloadblock, moved off thedefand onto an@!overridetargeting an otherwise-plain method:Actual
wrap_hash(matches overload #1) resolves fine.wrap_str(needsoverload #2) instead gets overload #1's
Array<Hash>param type andArray<Hash>return type forced onto it -- a genuine false positive,since
Array<String>is valid input per the second overload.Expected
@!override-attached@overloads dispatch per call site identically to@overloads on a realdef-- the two reproductions above shouldproduce the same (clean) result.
Impact
This blocks using
@!override/config/annotations_*.rb-style localstubs to give multiple, argument-dependent signatures to third-party gem
methods whose source can't be edited directly -- exactly the case
@!overrideexists for. A single generic (@generic T) signature isalso not always sufficient (e.g. when a method's return type genuinely
differs by argument category, not just by a uniform type parameter), so
@overloadis the only way to express that -- and it's brokenspecifically in the one context (
@!override) where it's needed most.Environment
2026-08-04, revision71f16f832d6e)