mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:24:57 +00:00
[ty] fix incorrect lazy scope narrowing (#19744)
## Summary This is a follow-up to #19321. Narrowing constraints introduced in a class scope were not applied even when they can be applied in lazy nested scopes. This PR fixes so that they are now applied. Conversely, there were cases where narrowing constraints were being applied in places where they should not, so it is also fixed. ## Test Plan Some TODOs in `narrow/conditionals/nested.md` are now work correctly.
This commit is contained in:
parent
64bcc8db2f
commit
351121c5c5
4 changed files with 12 additions and 5 deletions
|
@ -363,11 +363,12 @@ def f(x: str | Literal[1] | None):
|
|||
x = None
|
||||
|
||||
def _():
|
||||
# No narrowing is performed on unresolved references.
|
||||
# error: [unresolved-reference]
|
||||
if x is not None:
|
||||
def _():
|
||||
if x != 1:
|
||||
reveal_type(x) # revealed: Never
|
||||
reveal_type(x) # revealed: None
|
||||
x = None
|
||||
|
||||
def f(const: str | Literal[1] | None):
|
||||
|
@ -375,8 +376,7 @@ def f(const: str | Literal[1] | None):
|
|||
if const is not None:
|
||||
def _():
|
||||
if const != 1:
|
||||
# TODO: should be `str`
|
||||
reveal_type(const) # revealed: str | None
|
||||
reveal_type(const) # revealed: str
|
||||
|
||||
class D:
|
||||
if const != 1:
|
||||
|
|
|
@ -356,7 +356,9 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
for nested_symbol in self.place_tables[popped_scope_id].symbols() {
|
||||
// For the same reason, symbols declared as nonlocal or global are not recorded.
|
||||
// Also, if the enclosing scope allows its members to be modified from elsewhere, the snapshot will not be recorded.
|
||||
if self.scopes[enclosing_scope_id].visibility().is_public() {
|
||||
// (In the case of class scopes, class variables can be modified from elsewhere, but this has no effect in nested scopes,
|
||||
// as class variables are not visible to them)
|
||||
if self.scopes[enclosing_scope_id].kind().is_module() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -251,6 +251,10 @@ impl ScopeKind {
|
|||
matches!(self, ScopeKind::Class)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_module(self) -> bool {
|
||||
matches!(self, ScopeKind::Module)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_type_parameter(self) -> bool {
|
||||
matches!(self, ScopeKind::Annotation | ScopeKind::TypeAlias)
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ bitflags! {
|
|||
const IS_DECLARED = 1 << 2;
|
||||
const MARKED_GLOBAL = 1 << 3;
|
||||
const MARKED_NONLOCAL = 1 << 4;
|
||||
/// true if the symbol is assigned more than once, or if it is assigned even though it is already in use
|
||||
const IS_REASSIGNED = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +93,7 @@ impl Symbol {
|
|||
}
|
||||
|
||||
pub(super) fn mark_bound(&mut self) {
|
||||
if self.is_bound() {
|
||||
if self.is_bound() || self.is_used() {
|
||||
self.insert_flags(SymbolFlags::IS_REASSIGNED);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue