@@ -27,8 +27,8 @@ mod test;
2727
2828pub use analysis:: Def ;
2929use analysis:: Analysis ;
30- pub use raw:: { name_space_for_def_kind, read_analysis_incremental , DefKind , Target } ;
31- pub use loader:: { AnalysisLoader , CargoAnalysisLoader } ;
30+ pub use raw:: { name_space_for_def_kind, read_analysis_from_files , CrateId , DefKind } ;
31+ pub use loader:: { AnalysisLoader , CargoAnalysisLoader , Target } ;
3232
3333use std:: collections:: HashMap ;
3434use std:: path:: { Path , PathBuf } ;
@@ -39,8 +39,8 @@ use std::u64;
3939#[ derive( Debug ) ]
4040pub struct AnalysisHost < L : AnalysisLoader = CargoAnalysisLoader > {
4141 analysis : Mutex < Option < Analysis > > ,
42- master_crate_map : Mutex < HashMap < String , u32 > > ,
43- loader : L ,
42+ master_crate_map : Mutex < HashMap < CrateId , u32 > > ,
43+ loader : Mutex < L > ,
4444}
4545
4646pub type AResult < T > = Result < T , AError > ;
@@ -72,10 +72,13 @@ impl SymbolResult {
7272
7373pub type Span = span:: Span < span:: ZeroIndexed > ;
7474
75+ /// A common identifier for definitions, references etc. This is effectively a
76+ /// `DefId` with globally unique crate number (instead of a compiler generated
77+ /// crate-local number).
7578#[ derive( Copy , Clone , Eq , PartialEq , Debug , Hash , new) ]
7679pub struct Id ( u64 ) ;
7780
78- // Used to indicate a missing index in the Id.
81+ /// Used to indicate a missing index in the Id.
7982pub const NULL : Id = Id ( u64:: MAX ) ;
8083
8184type Blacklist < ' a > = & ' a [ & ' static str ] ;
@@ -95,10 +98,7 @@ impl AnalysisHost<CargoAnalysisLoader> {
9598 AnalysisHost {
9699 analysis : Mutex :: new ( None ) ,
97100 master_crate_map : Mutex :: new ( HashMap :: new ( ) ) ,
98- loader : CargoAnalysisLoader {
99- path_prefix : Mutex :: new ( None ) ,
100- target,
101- } ,
101+ loader : Mutex :: new ( CargoAnalysisLoader :: new ( target) ) ,
102102 }
103103 }
104104}
@@ -108,7 +108,7 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
108108 Self {
109109 analysis : Mutex :: new ( None ) ,
110110 master_crate_map : Mutex :: new ( HashMap :: new ( ) ) ,
111- loader,
111+ loader : Mutex :: new ( loader ) ,
112112 }
113113 }
114114
@@ -117,20 +117,24 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
117117 /// passing in directly.
118118 pub fn reload_from_analysis (
119119 & self ,
120- analysis : data:: Analysis ,
120+ analysis : Vec < data:: Analysis > ,
121121 path_prefix : & Path ,
122122 base_dir : & Path ,
123123 blacklist : Blacklist ,
124124 ) -> AResult < ( ) > {
125125 self . reload_with_blacklist ( path_prefix, base_dir, blacklist) ?;
126126
127+ let crates: Vec < _ > = analysis. into_iter ( )
128+ . map ( |analysis| raw:: Crate :: new ( analysis, SystemTime :: now ( ) ) )
129+ . collect ( ) ;
130+
127131 lowering:: lower (
128- vec ! [ raw :: Crate :: new ( analysis , SystemTime :: now ( ) , None ) ] ,
132+ crates ,
129133 base_dir,
130134 self ,
131- |host, per_crate, path | {
135+ |host, per_crate, id | {
132136 let mut a = host. analysis . lock ( ) ?;
133- a. as_mut ( ) . unwrap ( ) . update ( per_crate , path ) ;
137+ a. as_mut ( ) . unwrap ( ) . update ( id , per_crate ) ;
134138 Ok ( ( ) )
135139 } ,
136140 )
@@ -152,29 +156,23 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
152156 base_dir,
153157 blacklist
154158 ) ;
155- let empty = {
156- let a = self . analysis . lock ( ) ?;
157- a. is_none ( )
158- } ;
159- if empty || self . loader . needs_hard_reload ( path_prefix) {
159+ let empty = self . analysis . lock ( ) ?. is_none ( ) ;
160+ if empty || self . loader . lock ( ) ?. needs_hard_reload ( path_prefix) {
160161 return self . hard_reload_with_blacklist ( path_prefix, base_dir, blacklist) ;
161162 }
162163
163- let timestamps = {
164- let a = self . analysis . lock ( ) ?;
165- a. as_ref ( ) . unwrap ( ) . timestamps ( )
166- } ;
167-
168- let raw_analysis = read_analysis_incremental ( & self . loader , timestamps, blacklist) ;
164+ let timestamps = self . analysis . lock ( ) ?. as_ref ( ) . unwrap ( ) . timestamps ( ) ;
165+ let loader = self . loader . lock ( ) ?;
166+ let raw_analysis = read_analysis_from_files ( & * loader, timestamps, blacklist) ;
169167
170- lowering:: lower ( raw_analysis, base_dir, self , |host, per_crate, path | {
168+ lowering:: lower ( raw_analysis, base_dir, self , |host, per_crate, id | {
171169 let mut a = host. analysis . lock ( ) ?;
172- a. as_mut ( ) . unwrap ( ) . update ( per_crate , path ) ;
170+ a. as_mut ( ) . unwrap ( ) . update ( id , per_crate ) ;
173171 Ok ( ( ) )
174172 } )
175173 }
176174
177- // Reloads the entire project's analysis data.
175+ /// Reloads the entire project's analysis data.
178176 pub fn hard_reload ( & self , path_prefix : & Path , base_dir : & Path ) -> AResult < ( ) > {
179177 self . hard_reload_with_blacklist ( path_prefix, base_dir, & [ ] )
180178 }
@@ -186,42 +184,42 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
186184 blacklist : Blacklist ,
187185 ) -> AResult < ( ) > {
188186 trace ! ( "hard_reload {:?} {:?}" , path_prefix, base_dir) ;
189- self . loader . set_path_prefix ( path_prefix) ;
190- let raw_analysis = read_analysis_incremental ( & self . loader , HashMap :: new ( ) , blacklist) ;
191-
192187 // We're going to create a dummy AnalysisHost that we will fill with data,
193188 // then once we're done, we'll swap its data into self.
194- let mut fresh_host = self . loader . fresh_host ( ) ;
189+ let mut fresh_host = self . loader . lock ( ) ? . fresh_host ( ) ;
195190 fresh_host. analysis = Mutex :: new ( Some ( Analysis :: new ( ) ) ) ;
196- let lowering_result = lowering:: lower (
197- raw_analysis,
198- base_dir,
199- & fresh_host,
200- |host, per_crate, path| {
201- host. analysis
202- . lock ( )
203- . unwrap ( )
204- . as_mut ( )
205- . unwrap ( )
206- . per_crate
207- . insert ( path, per_crate) ;
208- Ok ( ( ) )
209- } ,
210- ) ;
211191
212- if let Err ( s) = lowering_result {
213- let mut a = self . analysis . lock ( ) ?;
214- * a = None ;
215- return Err ( s) ;
192+ {
193+ let mut fresh_loader = fresh_host. loader . lock ( ) . unwrap ( ) ;
194+ fresh_loader. set_path_prefix ( path_prefix) ; // TODO: Needed?
195+
196+ let raw_analysis = read_analysis_from_files ( & * fresh_loader,
197+ HashMap :: new ( ) ,
198+ blacklist) ;
199+ lowering:: lower ( raw_analysis, base_dir, & fresh_host, |host, per_crate, id| {
200+ let mut a = host. analysis . lock ( ) ?;
201+ a. as_mut ( ) . unwrap ( ) . update ( id, per_crate) ;
202+ Ok ( ( ) )
203+ } ) ?;
216204 }
217205
218- {
219- let mut mcm = self . master_crate_map . lock ( ) ?;
220- * mcm = fresh_host. master_crate_map . into_inner ( ) . unwrap ( ) ;
206+ // To guarantee a consistent state and no corruption in case an error
207+ // happens during reloading, we need to swap data with a dummy host in
208+ // a single atomic step. We can't lock and swap every member at a time,
209+ // as this can possibly lead to inconsistent state, but now this can possibly
210+ // deadlock, which isn't that good. Ideally we should have guaranteed
211+ // exclusive access to AnalysisHost as a whole to perform a reliable swap.
212+ macro_rules! swap_mutex_fields {
213+ ( $( $name: ident) ,* ) => {
214+ // First, we need exclusive access to every field before swapping
215+ $( let mut $name = self . $name. lock( ) ?; ) *
216+ // Then, we can swap every field
217+ $( * $name = fresh_host. $name. into_inner( ) . unwrap( ) ; ) *
218+ } ;
221219 }
222220
223- let mut a = self . analysis . lock ( ) ? ;
224- * a = Some ( fresh_host . analysis . into_inner ( ) . unwrap ( ) . unwrap ( ) ) ;
221+ swap_mutex_fields ! ( analysis , master_crate_map , loader ) ;
222+
225223 Ok ( ( ) )
226224 }
227225
@@ -275,7 +273,7 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
275273 pub fn def_roots ( & self ) -> AResult < Vec < ( Id , String ) > > {
276274 self . with_analysis ( |a| {
277275 Some (
278- a. for_all_crates ( |c| c. root_id . map ( |id| vec ! [ ( id, c. name. clone( ) ) ] ) ) ,
276+ a. for_all_crates ( |c| c. root_id . map ( |id| vec ! [ ( id, c. crate_id . name. clone( ) ) ] ) ) ,
279277 )
280278 } )
281279 }
@@ -448,7 +446,7 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
448446 // e.g., https://github.com/rust-lang/rust/blob/master/src/liballoc/string.rs#L261-L263
449447 pub fn src_url ( & self , span : & Span ) -> AResult < String > {
450448 // FIXME would be nice not to do this every time.
451- let path_prefix = & self . loader . abs_path_prefix ( ) ;
449+ let path_prefix = self . loader . lock ( ) . unwrap ( ) . abs_path_prefix ( ) ;
452450
453451 self . with_analysis ( |a| {
454452 a. def_id_for_span ( span) . and_then ( |id| {
0 commit comments