@@ -48,8 +48,8 @@ use crate::semantic_index::scope::{
4848use crate :: semantic_index:: scope:: { Scope , ScopeId , ScopeKind , ScopeLaziness } ;
4949use crate :: semantic_index:: symbol:: { ScopedSymbolId , Symbol } ;
5050use crate :: semantic_index:: use_def:: {
51- EnclosingSnapshotKey , FlowSnapshot , PreviousDefinitions , ScopedEnclosingSnapshotId ,
52- UseDefMapBuilder ,
51+ EnclosingSnapshotKey , FlowSnapshot , PreviousDefinitions , ScopedDefinitionId ,
52+ ScopedEnclosingSnapshotId , UseDefMapBuilder ,
5353} ;
5454use crate :: semantic_index:: {
5555 ExpressionsScopeMap , LoopHeader , LoopToken , SemanticIndex , VisibleAncestorsIter ,
@@ -845,12 +845,13 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
845845 }
846846
847847 /// Create loop header definitions for all places that are bound within a loop. Return the
848- /// `LoopToken` referenced by those definitions, and the set of bound place IDs.
848+ /// `LoopToken` referenced by those definitions, the set of bound place IDs, and the lower
849+ /// bound `ScopedDefinitionId` for definitions created within the loop.
849850 fn synthesize_loop_header_definitions (
850851 & mut self ,
851852 loop_stmt : LoopStmtRef < ' ast > ,
852853 bound_places : Vec < PlaceExpr > ,
853- ) -> ( LoopToken < ' db > , FxHashSet < ScopedPlaceId > ) {
854+ ) -> ( LoopToken < ' db > , FxHashSet < ScopedPlaceId > , ScopedDefinitionId ) {
854855 let loop_token = LoopToken :: new ( self . db ) ;
855856 let mut bound_place_ids: FxHashSet < ScopedPlaceId > = FxHashSet :: default ( ) ;
856857 for place_expr in bound_places {
@@ -865,7 +866,8 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
865866 self . push_additional_definition ( place_id, loop_header_ref) ;
866867 }
867868 }
868- ( loop_token, bound_place_ids)
869+ let loop_min_definition_id = self . current_use_def_map_mut ( ) . next_definition_id ( ) ;
870+ ( loop_token, bound_place_ids, loop_min_definition_id)
869871 }
870872
871873 /// Build a `LoopHeader` that tracks all the variables bound in a loop, which will be visible
@@ -876,13 +878,18 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
876878 & mut self ,
877879 loop_header_places : & FxHashSet < ScopedPlaceId > ,
878880 loop_token : LoopToken < ' db > ,
881+ loop_min_definition_id : ScopedDefinitionId ,
879882 ) {
880883 let mut loop_header = LoopHeader :: new ( ) ;
881884 let use_def = self . current_use_def_map_mut ( ) ;
882- // Collect bindings.
885+ // Collect all the bindings within the loop that reached a loop back edge. Use the minimum
886+ // definition ID to filter out all the pre-loop bindings. The loop header doesn't shadow
887+ // them, so there's no need to duplicate them.
883888 for place_id in loop_header_places {
884889 for live_binding in use_def. loop_back_bindings ( * place_id) {
885- loop_header. add_binding ( * place_id, live_binding) ;
890+ if live_binding. binding >= loop_min_definition_id {
891+ loop_header. add_binding ( * place_id, live_binding) ;
892+ }
886893 }
887894 }
888895 // Mark the reachability and narrowing constraints as used.
@@ -2225,8 +2232,10 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
22252232
22262233 // Collect all the loop-back bindings (including the `continue` states we just
22272234 // merged) and populate the `LoopHeader`.
2228- if let Some ( ( loop_token, bound_place_ids) ) = maybe_loop_header_info {
2229- self . populate_loop_header ( & bound_place_ids, loop_token) ;
2235+ if let Some ( ( loop_token, bound_place_ids, loop_min_definition_id) ) =
2236+ maybe_loop_header_info
2237+ {
2238+ self . populate_loop_header ( & bound_place_ids, loop_token, loop_min_definition_id) ;
22302239 }
22312240
22322241 // We execute the `else` branch once the condition evaluates to false. This could
@@ -2333,8 +2342,10 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
23332342
23342343 // Collect all the loop-back bindings (including the `continue` states we just
23352344 // merged) and populate the `LoopHeader`.
2336- if let Some ( ( loop_token, bound_place_ids) ) = maybe_loop_header_info {
2337- self . populate_loop_header ( & bound_place_ids, loop_token) ;
2345+ if let Some ( ( loop_token, bound_place_ids, loop_min_definition_id) ) =
2346+ maybe_loop_header_info
2347+ {
2348+ self . populate_loop_header ( & bound_place_ids, loop_token, loop_min_definition_id) ;
23382349 }
23392350
23402351 // We may execute the `else` clause without ever executing the body, so merge in
0 commit comments