Description
We've repeatedly seen issues where mypy emits an error that looks like type "foo" does not match type "foo"
, where the two types in question are identical as printed. That's super confusing for a user and makes mypy look quite buggy -- why is it saying this type doesn't match itself?
There are two recurring causes for this kind of symptom that I can recall seeing:
- suppressing long lists inside tuples and unions;
- rendering different types identically with the string "None".
We should probably stop suppressing long lists -- if the type is complicated, it's complicated, and if there's an error the user almost surely would rather see it whatever it is -- but those are at least mitigated by more or less explicitly being elliptical.
The cases with "None" vs "None" are extra confusing because there's nothing the user can see that at all points to why mypy could possibly consider these to be two different types internally. After all, they're just None! -- what internal structure does that have? The most recent instance I've run into is #1956 today.
Our messages would be more informative in these cases if we rendered Void
and NoneTyp
differently -- so at least one of them wasn't simply the string "None". This may show a bit of puzzling complexity to the user... but it's complexity that's really there in mypy's behavior, and it's probably better for the user to be given a hope of seeing its work. (It's possible that per #1278 and #1847 the ultimate solution should be to eliminate that complexity in the behavior, at which point it'll disappear from the user's view as well and in total honesty.)
For example, based on the docstring of Void
:
class Void(Type):
"""The return type 'None'.
This can only be used as the return type in a callable type and as
the result type of calling such callable.
"""
perhaps it could be rendered as something like NoneRet
-- recognizably connected to "None" but gesturing at its more specific nature.