Restore existing bindings when unbinding caught exceptions (#5256)
## Summary
In the latest release, we made some improvements to the semantic model,
but our modifications to exception-unbinding are causing some
false-positives. For example:
```py
try:
v = 3
except ImportError as v:
print(v)
else:
print(v)
```
In the latest release, we started unbinding `v` after the `except`
handler. (We used to restore the existing binding, the `v = 3`, but this
was quite complicated.) Because we don't have full branch analysis, we
can't then know that `v` is still bound in the `else` branch.
The solution here modifies `resolve_read` to skip-lookup when hitting
unbound exceptions. So when store the "unbind" for `except ImportError
as v`, we save the binding that it shadowed `v = 3`, and skip to that.
Closes #5249.
Closes #5250.
This commit is contained in:
@@ -75,7 +75,7 @@ impl<'a> Binding<'a> {
|
||||
pub const fn is_unbound(&self) -> bool {
|
||||
matches!(
|
||||
self.kind,
|
||||
BindingKind::Annotation | BindingKind::Deletion | BindingKind::UnboundException
|
||||
BindingKind::Annotation | BindingKind::Deletion | BindingKind::UnboundException(_)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -427,7 +427,11 @@ pub enum BindingKind<'a> {
|
||||
///
|
||||
/// After the `except` block, `x` is unbound, despite the lack
|
||||
/// of an explicit `del` statement.
|
||||
UnboundException,
|
||||
///
|
||||
///
|
||||
/// Stores the ID of the binding that was shadowed in the enclosing
|
||||
/// scope, if any.
|
||||
UnboundException(Option<BindingId>),
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
||||
Reference in New Issue
Block a user