-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
disambiguate booleans on conditions ("and" & "or" operators) #1698
Comments
Mypy does draw conclusions from Boolean operators and conditional statements, but it has limited understanding. Maybe only a slight refinement is needed? Looking at the code it seems that match could have the following values:
Then the I'm not sure exactly how to fix this but I think it is in principle possible. It's possible that there's a complication because the current stubs for re.pyi claim that search() returns a Match -- it should be an Optional[Match]. Once strict optional checking lands that should be fixed; but it would be fine to fix now. I don't think it's the cause of this problem though -- I'm just warning that fixing it (and strict optional checking) may interfere with any fix you could come up with for the issue at hand. |
Having separate, internal types for |
@pdmccormick suggested the same thing at PyCon in the context of #1477. I like the idea, but we'd need to find a way to continue to infer the types |
We also discussed the introduction of types like I agree that when inferring types of variables, mypy should probably promote all refinement types to the corresponding non-refinement type when there is no explicit type annotation. |
I'm not sure we want these to be subtypes of bool, actually, because many other types are also used for their truthiness. Instead, I think we should track the truthiness of all objects. Tracking truthiness universally should be both simpler to implement and more broadly useful. |
@ddfisher I agree on the "broadly useful" aspect, but I'm not sure about the "simpler" to implement. This should require ad-hoc rules for builtins (for example, [] is falsish, list.append always makes a list true-ish). It would help in |
Yeah, I agree. I didn't intend to suggest that we should track truthiness in all circumstances. I was thinking more along the lines of your initial example when |
OK, I'm starting to work on this, given that it's not a trivial change. Here's an outline of what I'm doing in case you want to suggest a different approach:
The following is an example: |
I see a few issues with this approach. At a high-level, they are:
I'd consider adding an |
I pushed a PR for this at #1989 It handles this case at least. I'll take a look to related issues to see if they improved with this |
This is an implementation of my proposed fix for #1698 ( #1698 (comment) ) Relevant differences from the description there: After the suggestion from @ddfisher I used class attributes in Type instead of wrapping Type objects. When I want to restrict a type I make a copy and override the can_be_true or can_be_false with instance attributes I didn't implement the rules for not after realising that I couldn't find a relevant example where it helped. It's easy to add later if we discover otherwise but I didn't want to bloat an already large PR I noticed that the deductive power was good enough to start detecting more dead code in unrelated test cases (see modifications in check-statements, check-modules and check-generics). There are some other improvements that I saw that could be made but I decided to stop here; if you think any of these are necessary I can add them: Covering the "not" operator, as mentioned above Renaming "find_isinstance_check" to something like "types_specialized_by_condition" which is more descriptive of its current purpose. I used copy.copy() followed by an update to create restricted version of types, perhaps there's a better/safer way to copy those (and even cache the restricted versions to reduce memory usage)
Closing since #1989 fixed this. |
I've noticed many false positive type errors related to "and" and "or" operators because they have the tendency to create union types. I'm working with some program which I reduced to the following example:
mypy figures out that the type of match is
Union[bool, re.Match]
(re.Match
actually doesn't exist, so I can't workaround this with anisinstance()
check here but this is not the main point here). So inside the if, I get:I understand why this happens, but I'm thinking that this could be analyzed statically, if mypy actually has some "always True" and "always False" types as subtypes of "Boolean". This could help in "and" and "or" expressions. The type of the expression above would be
Union[FalseType, re.Match]
. Which can be analyzed in an if removing the "FalseType" option from the Union, which gives an accurate typing of re.Match.A dual situation can be found if you have
boolexp or other_exp
which could be typed asUnion[TrueType, other_type]
.A possible generalization of this is having additional type information for all types saying "can be true-ish", "can be false-ish"; and that type information can be narrowed down on boolean operators and ifs.
On first sight, these ideas may look like going beyond the idea of a type checker and more into a program verifier but that's not actually what I'm proposing; the thing is that in actual programs this kind of checks are actually a way to narrow down union types, and my increase the effectiveness of mypy as a typechecker.
The text was updated successfully, but these errors were encountered: