@@ -263,7 +263,7 @@ use self::symbol_state::{
263263 LiveBindingsIterator , LiveDeclaration , LiveDeclarationsIterator , ScopedDefinitionId ,
264264 SymbolBindings , SymbolDeclarations , SymbolState ,
265265} ;
266- use crate :: semantic_index:: ast_ids:: ScopedUseId ;
266+ use crate :: semantic_index:: ast_ids:: { ScopedExpressionId , ScopedUseId } ;
267267use crate :: semantic_index:: definition:: Definition ;
268268use crate :: semantic_index:: narrowing_constraints:: {
269269 NarrowingConstraints , NarrowingConstraintsBuilder , NarrowingConstraintsIterator ,
@@ -297,8 +297,8 @@ pub(crate) struct UseDefMap<'db> {
297297 /// [`SymbolBindings`] reaching a [`ScopedUseId`].
298298 bindings_by_use : IndexVec < ScopedUseId , SymbolBindings > ,
299299
300- /// Tracks whether or not a given use of a symbol is reachable from the start of the scope.
301- reachability_by_use : IndexVec < ScopedUseId , ScopedVisibilityConstraintId > ,
300+ /// Tracks whether or not a given expression is reachable from the start of the scope.
301+ expression_reachability : FxHashMap < ScopedExpressionId , ScopedVisibilityConstraintId > ,
302302
303303 /// If the definition is a binding (only) -- `x = 1` for example -- then we need
304304 /// [`SymbolDeclarations`] to know whether this binding is permitted by the live declarations.
@@ -359,8 +359,26 @@ impl<'db> UseDefMap<'db> {
359359 . is_always_false ( )
360360 }
361361
362- pub ( super ) fn is_symbol_use_reachable ( & self , db : & dyn crate :: Db , use_id : ScopedUseId ) -> bool {
363- self . is_reachable ( db, self . reachability_by_use [ use_id] )
362+ /// Check whether or not a given expression is reachable from the start of the scope. This
363+ /// is a local analysis which does not capture the possibility that the entire scope might
364+ /// be unreachable. Use `SemanticIndex::is_expression_reachable` for the global analysis.
365+ #[ track_caller]
366+ pub ( super ) fn is_expression_reachable (
367+ & self ,
368+ db : & dyn crate :: Db ,
369+ expression_id : ScopedExpressionId ,
370+ ) -> bool {
371+ !self
372+ . visibility_constraints
373+ . evaluate (
374+ db,
375+ & self . predicates ,
376+ * self
377+ . expression_reachability
378+ . get ( & expression_id)
379+ . expect ( "only called on expressions with recorded reachability" ) ,
380+ )
381+ . is_always_false ( )
364382 }
365383
366384 pub ( crate ) fn public_bindings (
@@ -617,8 +635,8 @@ pub(super) struct UseDefMapBuilder<'db> {
617635 /// The use of `x` is recorded with a reachability constraint of `[test]`.
618636 pub ( super ) reachability : ScopedVisibilityConstraintId ,
619637
620- /// Tracks whether or not a given use of a symbol is reachable from the start of the scope.
621- reachability_by_use : IndexVec < ScopedUseId , ScopedVisibilityConstraintId > ,
638+ /// Tracks whether or not a given expression is reachable from the start of the scope.
639+ expression_reachability : FxHashMap < ScopedExpressionId , ScopedVisibilityConstraintId > ,
622640
623641 /// Live declarations for each so-far-recorded binding.
624642 declarations_by_binding : FxHashMap < Definition < ' db > , SymbolDeclarations > ,
@@ -644,7 +662,7 @@ impl Default for UseDefMapBuilder<'_> {
644662 scope_start_visibility : ScopedVisibilityConstraintId :: ALWAYS_TRUE ,
645663 bindings_by_use : IndexVec :: new ( ) ,
646664 reachability : ScopedVisibilityConstraintId :: ALWAYS_TRUE ,
647- reachability_by_use : IndexVec :: new ( ) ,
665+ expression_reachability : FxHashMap :: default ( ) ,
648666 declarations_by_binding : FxHashMap :: default ( ) ,
649667 bindings_by_declaration : FxHashMap :: default ( ) ,
650668 symbol_states : IndexVec :: new ( ) ,
@@ -799,16 +817,27 @@ impl<'db> UseDefMapBuilder<'db> {
799817 symbol_state. record_binding ( def_id, self . scope_start_visibility ) ;
800818 }
801819
802- pub ( super ) fn record_use ( & mut self , symbol : ScopedSymbolId , use_id : ScopedUseId ) {
820+ pub ( super ) fn record_use (
821+ & mut self ,
822+ symbol : ScopedSymbolId ,
823+ use_id : ScopedUseId ,
824+ expression_id : ScopedExpressionId ,
825+ ) {
803826 // We have a use of a symbol; clone the current bindings for that symbol, and record them
804827 // as the live bindings for this use.
805828 let new_use = self
806829 . bindings_by_use
807830 . push ( self . symbol_states [ symbol] . bindings ( ) . clone ( ) ) ;
808831 debug_assert_eq ! ( use_id, new_use) ;
809832
810- let new_use = self . reachability_by_use . push ( self . reachability ) ;
811- debug_assert_eq ! ( use_id, new_use) ;
833+ // Track reachability of all uses of symbols to silence `unresolved-reference`
834+ // diagnostics in unreachable code.
835+ self . record_expression_reachability ( expression_id) ;
836+ }
837+
838+ pub ( super ) fn record_expression_reachability ( & mut self , expression_id : ScopedExpressionId ) {
839+ self . expression_reachability
840+ . insert ( expression_id, self . reachability ) ;
812841 }
813842
814843 pub ( super ) fn snapshot_eager_bindings (
@@ -905,7 +934,6 @@ impl<'db> UseDefMapBuilder<'db> {
905934 self . all_definitions . shrink_to_fit ( ) ;
906935 self . symbol_states . shrink_to_fit ( ) ;
907936 self . bindings_by_use . shrink_to_fit ( ) ;
908- self . reachability_by_use . shrink_to_fit ( ) ;
909937 self . declarations_by_binding . shrink_to_fit ( ) ;
910938 self . bindings_by_declaration . shrink_to_fit ( ) ;
911939 self . eager_bindings . shrink_to_fit ( ) ;
@@ -916,7 +944,7 @@ impl<'db> UseDefMapBuilder<'db> {
916944 narrowing_constraints : self . narrowing_constraints . build ( ) ,
917945 visibility_constraints : self . visibility_constraints . build ( ) ,
918946 bindings_by_use : self . bindings_by_use ,
919- reachability_by_use : self . reachability_by_use ,
947+ expression_reachability : self . expression_reachability ,
920948 public_symbols : self . symbol_states ,
921949 declarations_by_binding : self . declarations_by_binding ,
922950 bindings_by_declaration : self . bindings_by_declaration ,
0 commit comments