[red-knot] Fix recording of negative visibility constraints (#17731)

## Summary

We were previously recording wrong reachability constraints for negative
branches. Instead of `[cond] AND (NOT [True])` below, we were recording
`[cond] AND (NOT ([cond] AND [True]))`, i.e. we were negating not just
the last predicate, but the `AND`-ed reachability constraint from last
clause. With this fix, we now record the correct constraints for the
example from #17723:

```py
def _(cond: bool):
    if cond:
        # reachability: [cond]
        if True:
            # reachability: [cond] AND [True]
            pass
        else:
            # reachability: [cond] AND (NOT [True])
            x
```

closes #17723 

## Test Plan

* Regression test.
* Verified the ecosystem changes
This commit is contained in:
David Peter 2025-04-30 09:32:13 +02:00 committed by GitHub
parent 2bb99df394
commit 4a621c2c12
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 18 additions and 1 deletions

View file

@ -304,6 +304,22 @@ else:
pass
```
And for nested `if` statements:
```py
def _(flag: bool):
if flag:
if sys.version_info >= (3, 11):
ExceptionGroup # no error here
else:
pass
if sys.version_info < (3, 11):
pass
else:
ExceptionGroup # no error here
```
The same works for ternary expressions:
```py

View file

@ -635,7 +635,8 @@ impl<'db> SemanticIndexBuilder<'db> {
.current_visibility_constraints_mut()
.add_atom(predicate_id);
self.current_use_def_map_mut()
.record_reachability_constraint(visibility_constraint)
.record_reachability_constraint(visibility_constraint);
visibility_constraint
}
/// Record the negation of a given reachability/visibility constraint.