@@ -47,8 +47,8 @@ use crate::semantic_index::scope::{
4747use crate :: semantic_index:: scope:: { Scope , ScopeId , ScopeKind , ScopeLaziness } ;
4848use crate :: semantic_index:: symbol:: { ScopedSymbolId , Symbol } ;
4949use crate :: semantic_index:: use_def:: {
50- EnclosingSnapshotKey , FlowSnapshot , PreviousDefinitions , ScopedEnclosingSnapshotId ,
51- UseDefMapBuilder ,
50+ EnclosingSnapshotKey , FlowSnapshot , PreviousDefinitions , ScopedDefinitionId ,
51+ ScopedEnclosingSnapshotId , UseDefMapBuilder ,
5252} ;
5353use crate :: semantic_index:: {
5454 ExpressionsScopeMap , LoopHeader , LoopToken , SemanticIndex , VisibleAncestorsIter ,
@@ -840,12 +840,13 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
840840 }
841841
842842 /// Create loop header definitions for all places that are bound within a loop. Return the
843- /// `LoopToken` referenced by those definitions, and the set of bound place IDs.
843+ /// `LoopToken` referenced by those definitions, the set of bound place IDs, and the lower
844+ /// bound `ScopedDefinitionId` for definitions created within the loop.
844845 fn synthesize_loop_header_definitions (
845846 & mut self ,
846847 loop_stmt : LoopStmtRef < ' ast > ,
847848 bound_places : Vec < PlaceExpr > ,
848- ) -> ( LoopToken < ' db > , FxHashSet < ScopedPlaceId > ) {
849+ ) -> ( LoopToken < ' db > , FxHashSet < ScopedPlaceId > , ScopedDefinitionId ) {
849850 let loop_token = LoopToken :: new ( self . db ) ;
850851 let mut bound_place_ids: FxHashSet < ScopedPlaceId > = FxHashSet :: default ( ) ;
851852 for place_expr in bound_places {
@@ -860,7 +861,8 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
860861 self . push_additional_definition ( place_id, loop_header_ref) ;
861862 }
862863 }
863- ( loop_token, bound_place_ids)
864+ let loop_min_definition_id = self . current_use_def_map_mut ( ) . next_definition_id ( ) ;
865+ ( loop_token, bound_place_ids, loop_min_definition_id)
864866 }
865867
866868 /// Build a `LoopHeader` that tracks all the variables bound in a loop, which will be visible
@@ -871,13 +873,18 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
871873 & mut self ,
872874 loop_header_places : & FxHashSet < ScopedPlaceId > ,
873875 loop_token : LoopToken < ' db > ,
876+ loop_min_definition_id : ScopedDefinitionId ,
874877 ) {
875878 let mut loop_header = LoopHeader :: new ( ) ;
876879 let use_def = self . current_use_def_map_mut ( ) ;
877- // Collect bindings.
880+ // Collect all the bindings within the loop that reached a loop back edge. Use the minimum
881+ // definition ID to filter out all the pre-loop bindings. The loop header doesn't shadow
882+ // them, so there's no need to duplicate them.
878883 for place_id in loop_header_places {
879884 for live_binding in use_def. loop_back_bindings ( * place_id) {
880- loop_header. add_binding ( * place_id, live_binding) ;
885+ if live_binding. binding >= loop_min_definition_id {
886+ loop_header. add_binding ( * place_id, live_binding) ;
887+ }
881888 }
882889 }
883890 // Mark the reachability and narrowing constraints as used.
@@ -2210,8 +2217,10 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
22102217
22112218 // Collect all the loop-back bindings (including the `continue` states we just
22122219 // merged) and populate the `LoopHeader`.
2213- if let Some ( ( loop_token, bound_place_ids) ) = maybe_loop_header_info {
2214- self . populate_loop_header ( & bound_place_ids, loop_token) ;
2220+ if let Some ( ( loop_token, bound_place_ids, loop_min_definition_id) ) =
2221+ maybe_loop_header_info
2222+ {
2223+ self . populate_loop_header ( & bound_place_ids, loop_token, loop_min_definition_id) ;
22152224 }
22162225
22172226 // We execute the `else` branch once the condition evaluates to false. This could
@@ -2318,8 +2327,10 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
23182327
23192328 // Collect all the loop-back bindings (including the `continue` states we just
23202329 // merged) and populate the `LoopHeader`.
2321- if let Some ( ( loop_token, bound_place_ids) ) = maybe_loop_header_info {
2322- self . populate_loop_header ( & bound_place_ids, loop_token) ;
2330+ if let Some ( ( loop_token, bound_place_ids, loop_min_definition_id) ) =
2331+ maybe_loop_header_info
2332+ {
2333+ self . populate_loop_header ( & bound_place_ids, loop_token, loop_min_definition_id) ;
23232334 }
23242335
23252336 // We may execute the `else` clause without ever executing the body, so merge in
0 commit comments