-
Notifications
You must be signed in to change notification settings - Fork 771
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
Unbound variable in "for/else" statement #919
Comments
Hm, the only way that this code can actually cause a NameError is if the list were non-empty and the for loop contained a break statement:
We can't know statically how many items a list contains, but the fact that we are saying "unbound" here without break is surprising. |
I would expect the sample above to produce this error for the reason that Jake mentioned. However, I noticed that it also produces the error if I replace I'm also considering making the "unbound" diagnostics part of the |
I still think these are valuable enough to leave on, if we can figure out the existing bugs like this one at least. We can see. |
The problem is that we can't eliminate all false positives. The sample above is a good example. From the perspective of a developer who knows that they're iterating over an empty list, they can tell that the "for" part of the loop will never be executed, and I think I'd prefer to revert my previous change, which watered down for iterator targets in for loops (i.e. it introduced false negatives) along with disabling unbound variable diagnostics when type checking is off. |
I don't think this is a good idea; to me this is similar to how we flag imports even though maybe there's some condition where they would work. It's something that greatly impacts the analysis and may produce confusing issues later when the type is listed as Unbound. I don't really think that we want to change the default if it's been working so well for the large bulk of the userbase due to a few issues that have been reported; I feel like many of them were actually revealing potential bugs anyway. Sure, it's a shame this "obvious" code would always bind And FWIW, this code runs fine, so it's not entirely just about what's in the list: for _ in [0]:
pass
else:
a = 0
print(a) |
I've reverted the earlier change because it not only weakened the check but also introduced a regression. I've also changed the default severity for the "reportUnboundVariable" diagnostic rule from "warning" to "none" when typeCheckingMode is "off". There are too many complaints of false positives from users who are not interested in receiving these warnings. |
Sorry for being late. It might be unclear in the example code, so let me explain a little further. Just think of an "for/else" statement. Code in the "for" clause runs conditionally, as the number of iterations can be zero. It is nearly impossible to tell how many the iterations will be. Meanwhile, the "else" clause runs conditionally when there is a "break", and is determined to run if there is no "break". I think it should be possible to tell whether there is one or more "break"s and these two situations should be treated differently. for _ in some_iterable:
a = 0
else:
b = 1
# `a` might be unbound but `b` should be bound. for _ in some_iterable:
a = 0
if some_condition_except_literal_false:
break
else:
b = 1
# Both `a` and `b` might be unbound. |
I agree. With my latest changes, the output of pylance (when the reportUnboundVariable diagnostic rule is enabled) matches what is shown in your two examples above. |
This issue has been fixed in version 2021.2.1, which we've just released. You can find the changelog here: https://github.com/microsoft/pylance-release/blob/main/CHANGELOG.md#202121-10-february-2021 |
Environment data
Example
Expected Behavior
No error reported
Other Info
"while/else" statement works correctly.
The text was updated successfully, but these errors were encountered: