Skip to content

Commit 351121c

Browse files
authored
[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.
1 parent 64bcc8d commit 351121c

File tree

4 files changed

+12
-5
lines changed

4 files changed

+12
-5
lines changed

crates/ty_python_semantic/resources/mdtest/narrow/conditionals/nested.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,20 +363,20 @@ def f(x: str | Literal[1] | None):
363363
x = None
364364

365365
def _():
366+
# No narrowing is performed on unresolved references.
366367
# error: [unresolved-reference]
367368
if x is not None:
368369
def _():
369370
if x != 1:
370-
reveal_type(x) # revealed: Never
371+
reveal_type(x) # revealed: None
371372
x = None
372373

373374
def f(const: str | Literal[1] | None):
374375
class C:
375376
if const is not None:
376377
def _():
377378
if const != 1:
378-
# TODO: should be `str`
379-
reveal_type(const) # revealed: str | None
379+
reveal_type(const) # revealed: str
380380

381381
class D:
382382
if const != 1:

crates/ty_python_semantic/src/semantic_index/builder.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,9 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
356356
for nested_symbol in self.place_tables[popped_scope_id].symbols() {
357357
// For the same reason, symbols declared as nonlocal or global are not recorded.
358358
// Also, if the enclosing scope allows its members to be modified from elsewhere, the snapshot will not be recorded.
359-
if self.scopes[enclosing_scope_id].visibility().is_public() {
359+
// (In the case of class scopes, class variables can be modified from elsewhere, but this has no effect in nested scopes,
360+
// as class variables are not visible to them)
361+
if self.scopes[enclosing_scope_id].kind().is_module() {
360362
continue;
361363
}
362364

crates/ty_python_semantic/src/semantic_index/scope.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ impl ScopeKind {
251251
matches!(self, ScopeKind::Class)
252252
}
253253

254+
pub(crate) const fn is_module(self) -> bool {
255+
matches!(self, ScopeKind::Module)
256+
}
257+
254258
pub(crate) const fn is_type_parameter(self) -> bool {
255259
matches!(self, ScopeKind::Annotation | ScopeKind::TypeAlias)
256260
}

crates/ty_python_semantic/src/semantic_index/symbol.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ bitflags! {
3636
const IS_DECLARED = 1 << 2;
3737
const MARKED_GLOBAL = 1 << 3;
3838
const MARKED_NONLOCAL = 1 << 4;
39+
/// true if the symbol is assigned more than once, or if it is assigned even though it is already in use
3940
const IS_REASSIGNED = 1 << 5;
4041
}
4142
}
@@ -92,7 +93,7 @@ impl Symbol {
9293
}
9394

9495
pub(super) fn mark_bound(&mut self) {
95-
if self.is_bound() {
96+
if self.is_bound() || self.is_used() {
9697
self.insert_flags(SymbolFlags::IS_REASSIGNED);
9798
}
9899

0 commit comments

Comments
 (0)