@@ -27,8 +27,8 @@ mod test;
27
27
28
28
pub use analysis:: Def ;
29
29
use 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 } ;
32
32
33
33
use std:: collections:: HashMap ;
34
34
use std:: path:: { Path , PathBuf } ;
@@ -39,8 +39,8 @@ use std::u64;
39
39
#[ derive( Debug ) ]
40
40
pub struct AnalysisHost < L : AnalysisLoader = CargoAnalysisLoader > {
41
41
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 > ,
44
44
}
45
45
46
46
pub type AResult < T > = Result < T , AError > ;
@@ -72,10 +72,13 @@ impl SymbolResult {
72
72
73
73
pub type Span = span:: Span < span:: ZeroIndexed > ;
74
74
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).
75
78
#[ derive( Copy , Clone , Eq , PartialEq , Debug , Hash , new) ]
76
79
pub struct Id ( u64 ) ;
77
80
78
- // Used to indicate a missing index in the Id.
81
+ /// Used to indicate a missing index in the Id.
79
82
pub const NULL : Id = Id ( u64:: MAX ) ;
80
83
81
84
type Blacklist < ' a > = & ' a [ & ' static str ] ;
@@ -95,10 +98,7 @@ impl AnalysisHost<CargoAnalysisLoader> {
95
98
AnalysisHost {
96
99
analysis : Mutex :: new ( None ) ,
97
100
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) ) ,
102
102
}
103
103
}
104
104
}
@@ -108,7 +108,7 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
108
108
Self {
109
109
analysis : Mutex :: new ( None ) ,
110
110
master_crate_map : Mutex :: new ( HashMap :: new ( ) ) ,
111
- loader,
111
+ loader : Mutex :: new ( loader ) ,
112
112
}
113
113
}
114
114
@@ -117,20 +117,24 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
117
117
/// passing in directly.
118
118
pub fn reload_from_analysis (
119
119
& self ,
120
- analysis : data:: Analysis ,
120
+ analysis : Vec < data:: Analysis > ,
121
121
path_prefix : & Path ,
122
122
base_dir : & Path ,
123
123
blacklist : Blacklist ,
124
124
) -> AResult < ( ) > {
125
125
self . reload_with_blacklist ( path_prefix, base_dir, blacklist) ?;
126
126
127
+ let crates: Vec < _ > = analysis. into_iter ( )
128
+ . map ( |analysis| raw:: Crate :: new ( analysis, SystemTime :: now ( ) ) )
129
+ . collect ( ) ;
130
+
127
131
lowering:: lower (
128
- vec ! [ raw :: Crate :: new ( analysis , SystemTime :: now ( ) , None ) ] ,
132
+ crates ,
129
133
base_dir,
130
134
self ,
131
- |host, per_crate, path | {
135
+ |host, per_crate, id | {
132
136
let mut a = host. analysis . lock ( ) ?;
133
- a. as_mut ( ) . unwrap ( ) . update ( per_crate , path ) ;
137
+ a. as_mut ( ) . unwrap ( ) . update ( id , per_crate ) ;
134
138
Ok ( ( ) )
135
139
} ,
136
140
)
@@ -152,29 +156,25 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
152
156
base_dir,
153
157
blacklist
154
158
) ;
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) {
160
161
return self . hard_reload_with_blacklist ( path_prefix, base_dir, blacklist) ;
161
162
}
162
163
163
- let timestamps = {
164
- let a = self . analysis . lock ( ) ?;
165
- a. as_ref ( ) . unwrap ( ) . timestamps ( )
164
+ let timestamps = self . analysis . lock ( ) ?. as_ref ( ) . unwrap ( ) . timestamps ( ) ;
165
+ let raw_analysis = {
166
+ let loader = self . loader . lock ( ) ?;
167
+ read_analysis_from_files ( & * loader, timestamps, blacklist)
166
168
} ;
167
169
168
- let raw_analysis = read_analysis_incremental ( & self . loader , timestamps, blacklist) ;
169
-
170
- lowering:: lower ( raw_analysis, base_dir, self , |host, per_crate, path| {
170
+ lowering:: lower ( raw_analysis, base_dir, self , |host, per_crate, id| {
171
171
let mut a = host. analysis . lock ( ) ?;
172
- a. as_mut ( ) . unwrap ( ) . update ( per_crate , path ) ;
172
+ a. as_mut ( ) . unwrap ( ) . update ( id , per_crate ) ;
173
173
Ok ( ( ) )
174
174
} )
175
175
}
176
176
177
- // Reloads the entire project's analysis data.
177
+ /// Reloads the entire project's analysis data.
178
178
pub fn hard_reload ( & self , path_prefix : & Path , base_dir : & Path ) -> AResult < ( ) > {
179
179
self . hard_reload_with_blacklist ( path_prefix, base_dir, & [ ] )
180
180
}
@@ -186,42 +186,42 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
186
186
blacklist : Blacklist ,
187
187
) -> AResult < ( ) > {
188
188
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
-
192
189
// We're going to create a dummy AnalysisHost that we will fill with data,
193
190
// then once we're done, we'll swap its data into self.
194
- let mut fresh_host = self . loader . fresh_host ( ) ;
191
+ let mut fresh_host = self . loader . lock ( ) ? . fresh_host ( ) ;
195
192
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
- ) ;
211
193
212
- if let Err ( s) = lowering_result {
213
- let mut a = self . analysis . lock ( ) ?;
214
- * a = None ;
215
- return Err ( s) ;
194
+ {
195
+ let mut fresh_loader = fresh_host. loader . lock ( ) . unwrap ( ) ;
196
+ fresh_loader. set_path_prefix ( path_prefix) ; // TODO: Needed?
197
+
198
+ let raw_analysis = read_analysis_from_files ( & * fresh_loader,
199
+ HashMap :: new ( ) ,
200
+ blacklist) ;
201
+ lowering:: lower ( raw_analysis, base_dir, & fresh_host, |host, per_crate, id| {
202
+ let mut a = host. analysis . lock ( ) ?;
203
+ a. as_mut ( ) . unwrap ( ) . update ( id, per_crate) ;
204
+ Ok ( ( ) )
205
+ } ) ?;
216
206
}
217
207
218
- {
219
- let mut mcm = self . master_crate_map . lock ( ) ?;
220
- * mcm = fresh_host. master_crate_map . into_inner ( ) . unwrap ( ) ;
208
+ // To guarantee a consistent state and no corruption in case an error
209
+ // happens during reloading, we need to swap data with a dummy host in
210
+ // a single atomic step. We can't lock and swap every member at a time,
211
+ // as this can possibly lead to inconsistent state, but now this can possibly
212
+ // deadlock, which isn't that good. Ideally we should have guaranteed
213
+ // exclusive access to AnalysisHost as a whole to perform a reliable swap.
214
+ macro_rules! swap_mutex_fields {
215
+ ( $( $name: ident) ,* ) => {
216
+ // First, we need exclusive access to every field before swapping
217
+ $( let mut $name = self . $name. lock( ) ?; ) *
218
+ // Then, we can swap every field
219
+ $( * $name = fresh_host. $name. into_inner( ) . unwrap( ) ; ) *
220
+ } ;
221
221
}
222
222
223
- let mut a = self . analysis . lock ( ) ? ;
224
- * a = Some ( fresh_host . analysis . into_inner ( ) . unwrap ( ) . unwrap ( ) ) ;
223
+ swap_mutex_fields ! ( analysis , master_crate_map , loader ) ;
224
+
225
225
Ok ( ( ) )
226
226
}
227
227
@@ -275,7 +275,12 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
275
275
pub fn def_roots ( & self ) -> AResult < Vec < ( Id , String ) > > {
276
276
self . with_analysis ( |a| {
277
277
Some (
278
- a. for_all_crates ( |c| c. root_id . map ( |id| vec ! [ ( id, c. name. clone( ) ) ] ) ) ,
278
+ a. per_crate
279
+ . iter ( )
280
+ . filter_map ( |( crate_id, data) | {
281
+ data. root_id . map ( |id| ( id, crate_id. name . clone ( ) ) )
282
+ } )
283
+ . collect ( )
279
284
)
280
285
} )
281
286
}
@@ -448,7 +453,7 @@ impl<L: AnalysisLoader> AnalysisHost<L> {
448
453
// e.g., https://github.com/rust-lang/rust/blob/master/src/liballoc/string.rs#L261-L263
449
454
pub fn src_url ( & self , span : & Span ) -> AResult < String > {
450
455
// FIXME would be nice not to do this every time.
451
- let path_prefix = & self . loader . abs_path_prefix ( ) ;
456
+ let path_prefix = self . loader . lock ( ) . unwrap ( ) . abs_path_prefix ( ) ;
452
457
453
458
self . with_analysis ( |a| {
454
459
a. def_id_for_span ( span) . and_then ( |id| {
0 commit comments