mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:25:17 +00:00
[red-knot] Consider all definitions after terminal statements unreachable (#15676)
`FlowSnapshot` now tracks a `reachable` bool, which indicates whether we have encountered a terminal statement on that control flow path. When merging flow states together, we skip any that have been marked unreachable. This ensures that bindings that can only be reached through unreachable paths are not considered visible. ## Test Plan The new mdtests failed (with incorrect `reveal_type` results, and spurious `possibly-unresolved-reference` errors) before adding the new visibility constraints. --------- Co-authored-by: Carl Meyer <carl@astral.sh>
This commit is contained in:
parent
e1c9d10863
commit
15d886a502
4 changed files with 686 additions and 22 deletions
|
@ -368,6 +368,12 @@ impl<'db> SemanticIndexBuilder<'db> {
|
|||
.record_visibility_constraint(VisibilityConstraint::VisibleIf(constraint))
|
||||
}
|
||||
|
||||
/// Records that all remaining statements in the current block are unreachable, and therefore
|
||||
/// not visible.
|
||||
fn mark_unreachable(&mut self) {
|
||||
self.current_use_def_map_mut().mark_unreachable();
|
||||
}
|
||||
|
||||
/// Records a [`VisibilityConstraint::Ambiguous`] constraint.
|
||||
fn record_ambiguous_visibility(&mut self) -> ScopedVisibilityConstraintId {
|
||||
self.current_use_def_map_mut()
|
||||
|
@ -1019,11 +1025,6 @@ where
|
|||
}
|
||||
self.visit_body(body);
|
||||
}
|
||||
ast::Stmt::Break(_) => {
|
||||
if self.loop_state().is_inside() {
|
||||
self.loop_break_states.push(self.flow_snapshot());
|
||||
}
|
||||
}
|
||||
|
||||
ast::Stmt::For(
|
||||
for_stmt @ ast::StmtFor {
|
||||
|
@ -1270,6 +1271,21 @@ where
|
|||
// - https://github.com/astral-sh/ruff/pull/13633#discussion_r1788626702
|
||||
self.visit_body(finalbody);
|
||||
}
|
||||
|
||||
ast::Stmt::Raise(_) | ast::Stmt::Return(_) | ast::Stmt::Continue(_) => {
|
||||
walk_stmt(self, stmt);
|
||||
// Everything in the current block after a terminal statement is unreachable.
|
||||
self.mark_unreachable();
|
||||
}
|
||||
|
||||
ast::Stmt::Break(_) => {
|
||||
if self.loop_state().is_inside() {
|
||||
self.loop_break_states.push(self.flow_snapshot());
|
||||
}
|
||||
// Everything in the current block after a terminal statement is unreachable.
|
||||
self.mark_unreachable();
|
||||
}
|
||||
|
||||
_ => {
|
||||
walk_stmt(self, stmt);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue