diff --git a/crates/ty_python_semantic/resources/mdtest/loops/while_loop.md b/crates/ty_python_semantic/resources/mdtest/loops/while_loop.md index 7e3a45e777d67..68a3805798392 100644 --- a/crates/ty_python_semantic/resources/mdtest/loops/while_loop.md +++ b/crates/ty_python_semantic/resources/mdtest/loops/while_loop.md @@ -477,8 +477,7 @@ def random() -> bool: x = 0 while random(): - # TODO: This should reveal `Literal[0]`. - reveal_type(x) # revealed: Literal[0, 2] + reveal_type(x) # revealed: Literal[0] if x == 1: x = 2 ``` diff --git a/crates/ty_python_semantic/src/place.rs b/crates/ty_python_semantic/src/place.rs index d58358462b470..ca08bf043ffc0 100644 --- a/crates/ty_python_semantic/src/place.rs +++ b/crates/ty_python_semantic/src/place.rs @@ -1159,12 +1159,12 @@ pub(crate) fn loop_header_reachability<'db>( fn loop_header_reachability_cycle_recover<'db>( _db: &'db dyn Db, - _cycle: &salsa::Cycle, + cycle: &salsa::Cycle, previous: &LoopHeaderReachability<'db>, result: LoopHeaderReachability<'db>, _definition: Definition<'db>, ) -> LoopHeaderReachability<'db> { - result.cycle_normalized(previous) + result.cycle_normalized(previous, cycle) } fn loop_header_reachability_impl<'db>( @@ -1236,10 +1236,16 @@ impl<'db> LoopHeaderReachability<'db> { fn cycle_normalized( self, previous: &LoopHeaderReachability<'db>, + cycle: &salsa::Cycle, ) -> LoopHeaderReachability<'db> { - let mut reachable_bindings = FxIndexSet::default(); - reachable_bindings.extend(previous.reachable_bindings.iter().copied()); - reachable_bindings.extend(self.reachable_bindings); + // Avoid losing precision for cycles that are soon to converge. + // See [`Type::cycle_normalized`] for more details. + let reachable_bindings = if cycle.iteration() <= 1 { + self.reachable_bindings + } else { + let previous_bindings = previous.reachable_bindings.iter().copied(); + previous_bindings.chain(self.reachable_bindings).collect() + }; LoopHeaderReachability { deleted_reachability: self.deleted_reachability,