You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Overloads defined for None and object get inferred as Any #3757
(This came up while playing with descriptors, where the first parameter of __get__ can be either None or an arbitrary object and you want different return types in the two cases.)
Example reproduction using mypy --strict-optional on 0.520:
fromtypingimport*@overloaddefa_or_1(obj: None) ->str:
...
@overloaddefa_or_1(obj: object) ->int:
# If you change the type of `obj` to e.g. AnyStr, the bug goes away
...
defa_or_1(obj):
ifobjisNone:
return'a'return1reveal_type(a_or_1('a string')) # correctly revealed as 'builtins.int'reveal_type(a_or_1(None)) # revealed as type Any (should be 'builtins.str')
Hmm, really? Without much knowledge of the underlying machinery, that seems surprising to me--#3256 is only a problem without strict-optional, and this test case only makes sense with strict-optional enabled. Also, this seems to have to do with some kind of special-casing of object, and object isn't mentioned at all in #3256. #3256 seems like a design problem for how to cope with None causing type overlaps, whereas this seems like it should straightforwardly just work (the testOverloadWithNone test case in the current unit tests fails if you replace the int annotation with object).
Sorry if there's some deeper reason I'm missing as to why they're actually the same! I'm interested in knowing because I was planning to try to fix this today :)
Hmm, ok, it appears to actually be intentional that None and object overlap in overloads. There's a test case testNoneMatchesObjectInOverload in check-optional.test, introduced in #1836 to solve #1766. The code that handles it is a special case in checkexpr.overload_arg_similarity:2653:
ifisinstance(actual, NoneTyp):
ifnotexperiments.STRICT_OPTIONAL:
# NoneTyp matches anything if we're not doing strict Optional checkingreturn2else:
# NoneType is a subtype of objectifisinstance(formal, Instance) andformal.type.fullname() =="builtins.object":
return2
I made a branch changing the return 2 to return 1 (meaning the types are compatible using type promotions), which fixes this issue and passes all other tests. But maybe that's an abuse of the meaning of "similarity" there? Let me know if this, or something similar, seems like a good direction.
Hey @ilinum or anyone else, wondering whether you have feedback on whether this is truly a duplicate, or whether my proposal (or something like it) seems like a good resolution?
Update: The original example still won't typecheck (by design), but we recently added code to master that special-cases and allows this kind of overload for specifically descriptors -- see #5093 for examples.
So, I think we can probably close this now? Feel free to reopen if anybody disagrees.
Activity
ilinum commentedon Jul 22, 2017
Thanks for reporting the issue!
This is a duplicate of #3256.
benkuhn commentedon Jul 22, 2017
Hmm, really? Without much knowledge of the underlying machinery, that seems surprising to me--#3256 is only a problem without strict-optional, and this test case only makes sense with strict-optional enabled. Also, this seems to have to do with some kind of special-casing of
object, andobjectisn't mentioned at all in #3256. #3256 seems like a design problem for how to cope withNonecausing type overlaps, whereas this seems like it should straightforwardly just work (thetestOverloadWithNonetest case in the current unit tests fails if you replace theintannotation withobject).Sorry if there's some deeper reason I'm missing as to why they're actually the same! I'm interested in knowing because I was planning to try to fix this today :)
benkuhn commentedon Jul 22, 2017
Hmm, ok, it appears to actually be intentional that
Noneandobjectoverlap in overloads. There's a test casetestNoneMatchesObjectInOverloadincheck-optional.test, introduced in #1836 to solve #1766. The code that handles it is a special case incheckexpr.overload_arg_similarity:2653:I made a branch changing the
return 2toreturn 1(meaning the types are compatible using type promotions), which fixes this issue and passes all other tests. But maybe that's an abuse of the meaning of "similarity" there? Let me know if this, or something similar, seems like a good direction.benkuhn commentedon Jul 23, 2017
Hey @ilinum or anyone else, wondering whether you have feedback on whether this is truly a duplicate, or whether my proposal (or something like it) seems like a good resolution?
ilinum commentedon Jul 24, 2017
Sorry, I was away for the weekend, so didn't see your comments until just now.
Yep, you're right this is not a duplicate of the #3256. I missed the fact that your example fails with
--strict-optional. Sorry!Your fix seems reasonable, I think it could work. It's probably worth sending a PR and seeing what other say.
ilevkivskyi commentedon May 20, 2018
Oops, wrong place, deleting the comment.
Michael0x2a commentedon Jun 15, 2018
Update: The original example still won't typecheck (by design), but we recently added code to master that special-cases and allows this kind of overload for specifically descriptors -- see #5093 for examples.
So, I think we can probably close this now? Feel free to reopen if anybody disagrees.