@@ -14,12 +14,13 @@ use crate::model::references::{ConstantReference, MethodRef};
1414use crate :: model:: string_ref:: StringRef ;
1515use crate :: stats;
1616
17- /// A definition or constant reference that uses a particular `NameId`.
18- /// Used as the value type in the `name_users ` reverse index.
17+ /// An entity whose validity depends on a particular `NameId`.
18+ /// Used as the value type in the `name_dependents ` reverse index.
1919#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
20- pub enum NameUser {
20+ pub enum NameDependent {
2121 Definition ( DefinitionId ) ,
2222 Reference ( ReferenceId ) ,
23+ Name ( NameId ) ,
2324}
2425
2526/// Items processed by the unified invalidation worklist.
@@ -72,13 +73,9 @@ pub struct Graph {
7273 /// Used during incremental invalidation to find names that need unresolving when a declaration is removed.
7374 declaration_to_names : IdentityHashMap < DeclarationId , IdentityHashSet < NameId > > ,
7475
75- /// Reverse index: for each `NameId`, which definitions and constant references use it.
76- /// Eliminates O(D+R) scans during invalidation.
77- name_users : IdentityHashMap < NameId , Vec < NameUser > > ,
78-
79- /// Reverse index: for each `NameId`, which other names depend on it
80- /// (via nesting or `parent_scope`). Used for cascade invalidation.
81- name_dependents : IdentityHashMap < NameId , IdentityHashSet < NameId > > ,
76+ /// Reverse index: for each `NameId`, what depends on it (definitions, references, and child names).
77+ /// Used during invalidation to efficiently find affected entities without scanning the full graph.
78+ name_dependents : IdentityHashMap < NameId , Vec < NameDependent > > ,
8279
8380 /// Accumulated work items from update/delete operations.
8481 /// Drained by `take_pending_work()` before resolution.
@@ -98,7 +95,6 @@ impl Graph {
9895 method_references : IdentityHashMap :: default ( ) ,
9996 position_encoding : Encoding :: default ( ) ,
10097 declaration_to_names : IdentityHashMap :: default ( ) ,
101- name_users : IdentityHashMap :: default ( ) ,
10298 name_dependents : IdentityHashMap :: default ( ) ,
10399 pending_work : Vec :: default ( ) ,
104100 }
@@ -578,19 +574,13 @@ impl Graph {
578574 let nesting_id = name_ref. nesting ( ) . as_ref ( ) . copied ( ) ;
579575 let parent_scope_id = name_ref. parent_scope ( ) . as_ref ( ) . copied ( ) ;
580576
581- // Remove this name from name_dependents of its nesting and parent_scope names
577+ // Remove this name from its nesting/parent_scope owners' dependent lists
582578 for dep_owner_id in [ nesting_id, parent_scope_id] . into_iter ( ) . flatten ( ) {
583- if let Some ( deps) = self . name_dependents . get_mut ( & dep_owner_id) {
584- deps. remove ( & name_id) ;
585- if deps. is_empty ( ) {
586- self . name_dependents . remove ( & dep_owner_id) ;
587- }
588- }
579+ self . remove_name_dependent ( dep_owner_id, NameDependent :: Name ( name_id) ) ;
589580 }
590581 }
591582
592583 self . name_dependents . remove ( & name_id) ;
593- self . name_users . remove ( & name_id) ;
594584 self . names . remove ( & name_id) ;
595585 }
596586
@@ -768,21 +758,29 @@ impl Graph {
768758 Entry :: Vacant ( entry) => {
769759 // Track nesting and parent_scope dependents for new names only
770760 if let Some ( nesting_id) = entry. insert ( name_ref) . nesting ( ) {
771- self . name_dependents . entry ( * nesting_id) . or_default ( ) . insert ( name_id) ;
761+ let deps = self . name_dependents . entry ( * nesting_id) . or_default ( ) ;
762+ let dep = NameDependent :: Name ( name_id) ;
763+ if !deps. contains ( & dep) {
764+ deps. push ( dep) ;
765+ }
772766 }
773767 if let Some ( parent_id) = self . names . get ( & name_id) . unwrap ( ) . parent_scope ( ) . as_ref ( ) {
774- self . name_dependents . entry ( * parent_id) . or_default ( ) . insert ( name_id) ;
768+ let deps = self . name_dependents . entry ( * parent_id) . or_default ( ) ;
769+ let dep = NameDependent :: Name ( name_id) ;
770+ if !deps. contains ( & dep) {
771+ deps. push ( dep) ;
772+ }
775773 }
776774 }
777775 }
778776 }
779777
780778 for ( definition_id, definition) in definitions {
781779 if let Some ( name_id) = definition. name_id ( ) {
782- self . name_users
780+ self . name_dependents
783781 . entry ( * name_id)
784782 . or_default ( )
785- . push ( NameUser :: Definition ( definition_id) ) ;
783+ . push ( NameDependent :: Definition ( definition_id) ) ;
786784 }
787785
788786 if self . definitions . insert ( definition_id, definition) . is_some ( ) {
@@ -793,10 +791,10 @@ impl Graph {
793791 }
794792
795793 for ( constant_ref_id, constant_ref) in constant_references {
796- self . name_users
794+ self . name_dependents
797795 . entry ( * constant_ref. name_id ( ) )
798796 . or_default ( )
799- . push ( NameUser :: Reference ( constant_ref_id) ) ;
797+ . push ( NameDependent :: Reference ( constant_ref_id) ) ;
800798
801799 work. push ( Unit :: ConstantRef ( constant_ref_id) ) ;
802800
@@ -907,7 +905,7 @@ impl Graph {
907905 declaration. remove_reference ( ref_id) ;
908906 }
909907
910- self . remove_name_user ( * constant_ref. name_id ( ) , NameUser :: Reference ( * ref_id) ) ;
908+ self . remove_name_dependent ( * constant_ref. name_id ( ) , NameDependent :: Reference ( * ref_id) ) ;
911909 self . untrack_name ( * constant_ref. name_id ( ) ) ;
912910 }
913911 }
@@ -919,19 +917,19 @@ impl Graph {
919917
920918 let definition = self . definitions . remove ( def_id) . unwrap ( ) ;
921919 if let Some ( name_id) = definition. name_id ( ) {
922- self . remove_name_user ( * name_id, NameUser :: Definition ( * def_id) ) ;
920+ self . remove_name_dependent ( * name_id, NameDependent :: Definition ( * def_id) ) ;
923921 }
924922 self . untrack_definition_strings ( & definition) ;
925923 }
926924 }
927925
928- /// Removes a specific user from the `name_users ` entry for `name_id`, cleaning up the entry
929- /// if no users remain.
930- fn remove_name_user ( & mut self , name_id : NameId , user : NameUser ) {
931- if let Some ( users ) = self . name_users . get_mut ( & name_id) {
932- users . retain ( |u | * u != user ) ;
933- if users . is_empty ( ) {
934- self . name_users . remove ( & name_id) ;
926+ /// Removes a specific dependent from the `name_dependents ` entry for `name_id`,
927+ /// cleaning up the entry if no dependents remain.
928+ fn remove_name_dependent ( & mut self , name_id : NameId , dependent : NameDependent ) {
929+ if let Some ( deps ) = self . name_dependents . get_mut ( & name_id) {
930+ deps . retain ( |d | * d != dependent ) ;
931+ if deps . is_empty ( ) {
932+ self . name_dependents . remove ( & name_id) ;
935933 }
936934 }
937935 }
@@ -987,13 +985,15 @@ impl Graph {
987985 }
988986 }
989987
990- // Unresolve names resolved to this declaration, queue their dependents
988+ // Unresolve names resolved to this declaration, queue their Name dependents
991989 if let Some ( name_set) = self . declaration_to_names . remove ( & decl_id) {
992990 for name_id in name_set {
993991 self . unresolve_name ( name_id) ;
994992 if let Some ( deps) = self . name_dependents . get ( & name_id) {
995993 for dep in deps {
996- queue. push ( InvalidationItem :: Name ( * dep) ) ;
994+ if let NameDependent :: Name ( dep_name_id) = dep {
995+ queue. push ( InvalidationItem :: Name ( * dep_name_id) ) ;
996+ }
997997 }
998998 }
999999 }
@@ -1047,12 +1047,14 @@ impl Graph {
10471047
10481048 work. push ( Unit :: Ancestors ( decl_id) ) ;
10491049
1050- // Queue dependents of resolved names (skipping seeds themselves)
1050+ // Queue Name dependents of resolved names (skipping seeds themselves)
10511051 if let Some ( name_set) = self . declaration_to_names . get ( & decl_id) {
10521052 for seed_name_id in name_set {
10531053 if let Some ( deps) = self . name_dependents . get ( seed_name_id) {
10541054 for dep in deps {
1055- queue. push ( InvalidationItem :: Name ( * dep) ) ;
1055+ if let NameDependent :: Name ( dep_name_id) = dep {
1056+ queue. push ( InvalidationItem :: Name ( * dep_name_id) ) ;
1057+ }
10561058 }
10571059 }
10581060 }
@@ -1076,31 +1078,31 @@ impl Graph {
10761078 return ;
10771079 }
10781080
1079- // Always propagate to dependents
1080- if let Some ( deps) = self . name_dependents . get ( & name_id) {
1081- for dep in deps {
1082- queue. push ( InvalidationItem :: Name ( * dep) ) ;
1081+ let dependents: Vec < NameDependent > = self . name_dependents . get ( & name_id) . cloned ( ) . unwrap_or_default ( ) ;
1082+
1083+ // Always propagate to Name dependents
1084+ for dep in & dependents {
1085+ if let NameDependent :: Name ( dep_name_id) = dep {
1086+ queue. push ( InvalidationItem :: Name ( * dep_name_id) ) ;
10831087 }
10841088 }
10851089
10861090 if self . has_unresolved_dependency ( name_id) {
10871091 // Structural cascade: the name's resolution is invalid
10881092 if let Some ( old_decl_id) = self . unresolve_name ( name_id) {
1089- let users: Vec < NameUser > = self . name_users . get ( & name_id) . cloned ( ) . unwrap_or_default ( ) ;
1090-
1091- for user in users {
1092- match user {
1093- NameUser :: Reference ( ref_id) => {
1093+ for dep in & dependents {
1094+ match dep {
1095+ NameDependent :: Reference ( ref_id) => {
10941096 if let Some ( decl) = self . declarations . get_mut ( & old_decl_id) {
1095- decl. remove_reference ( & ref_id) ;
1097+ decl. remove_reference ( ref_id) ;
10961098 }
1097- work. push ( Unit :: ConstantRef ( ref_id) ) ;
1099+ work. push ( Unit :: ConstantRef ( * ref_id) ) ;
10981100 }
1099- NameUser :: Definition ( def_id) => {
1100- work. push ( Unit :: Definition ( def_id) ) ;
1101+ NameDependent :: Definition ( def_id) => {
1102+ work. push ( Unit :: Definition ( * def_id) ) ;
11011103
11021104 if let Some ( decl) = self . declarations . get_mut ( & old_decl_id) {
1103- decl. remove_definition ( & def_id) ;
1105+ decl. remove_definition ( def_id) ;
11041106 }
11051107
11061108 if self
@@ -1111,29 +1113,21 @@ impl Graph {
11111113 queue. push ( InvalidationItem :: Declaration ( old_decl_id) ) ;
11121114 }
11131115 }
1116+ NameDependent :: Name ( _) => { } // already propagated above
11141117 }
11151118 }
11161119 }
11171120 } else {
11181121 // Ancestor change only: re-evaluate constant references under this name
1119- let ref_ids: Vec < ReferenceId > = self
1120- . name_users
1121- . get ( & name_id)
1122- . into_iter ( )
1123- . flatten ( )
1124- . filter_map ( |u| match u {
1125- NameUser :: Reference ( id) => Some ( * id) ,
1126- NameUser :: Definition ( _) => None ,
1127- } )
1128- . collect ( ) ;
1129-
11301122 let is_resolved = matches ! ( self . names. get( & name_id) , Some ( NameRef :: Resolved ( _) ) ) ;
11311123
1132- for ref_id in ref_ids {
1133- if is_resolved {
1134- self . unresolve_reference ( ref_id) ;
1124+ for dep in & dependents {
1125+ if let NameDependent :: Reference ( ref_id) = dep {
1126+ if is_resolved {
1127+ self . unresolve_reference ( * ref_id) ;
1128+ }
1129+ work. push ( Unit :: ConstantRef ( * ref_id) ) ;
11351130 }
1136- work. push ( Unit :: ConstantRef ( ref_id) ) ;
11371131 }
11381132 }
11391133 }
0 commit comments