@@ -78,7 +78,7 @@ pub fn borrowck_query(
78
78
. map ( |body| {
79
79
let body = body?;
80
80
Ok ( BorrowckResult {
81
- mutability_of_locals : mutability_of_locals ( & body) ,
81
+ mutability_of_locals : mutability_of_locals ( db , & body) ,
82
82
moved_out_of_ref : moved_out_of_ref ( db, & body) ,
83
83
mir_body : body,
84
84
} )
@@ -186,10 +186,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
186
186
result
187
187
}
188
188
189
- fn is_place_direct ( lvalue : & Place ) -> bool {
190
- !lvalue. projection . iter ( ) . any ( |x| * x == ProjectionElem :: Deref )
191
- }
192
-
189
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
193
190
enum ProjectionCase {
194
191
/// Projection is a local
195
192
Direct ,
@@ -199,12 +196,14 @@ enum ProjectionCase {
199
196
Indirect ,
200
197
}
201
198
202
- fn place_case ( lvalue : & Place ) -> ProjectionCase {
199
+ fn place_case ( db : & dyn HirDatabase , body : & MirBody , lvalue : & Place ) -> ProjectionCase {
203
200
let mut is_part_of = false ;
204
- for proj in lvalue. projection . iter ( ) . rev ( ) {
201
+ let mut ty = body. locals [ lvalue. local ] . ty . clone ( ) ;
202
+ for proj in lvalue. projection . iter ( ) {
205
203
match proj {
206
- ProjectionElem :: Deref => return ProjectionCase :: Indirect , // It's indirect
207
- ProjectionElem :: ConstantIndex { .. }
204
+ ProjectionElem :: Deref if ty. as_adt ( ) . is_none ( ) => return ProjectionCase :: Indirect , // It's indirect in case of reference and raw
205
+ ProjectionElem :: Deref // It's direct in case of `Box<T>`
206
+ | ProjectionElem :: ConstantIndex { .. }
208
207
| ProjectionElem :: Subslice { .. }
209
208
| ProjectionElem :: Field ( _)
210
209
| ProjectionElem :: TupleOrClosureField ( _)
@@ -213,6 +212,23 @@ fn place_case(lvalue: &Place) -> ProjectionCase {
213
212
}
214
213
ProjectionElem :: OpaqueCast ( _) => ( ) ,
215
214
}
215
+ ty = proj. projected_ty (
216
+ ty,
217
+ db,
218
+ |c, subst, f| {
219
+ let ( def, _) = db. lookup_intern_closure ( c. into ( ) ) ;
220
+ let infer = db. infer ( def) ;
221
+ let ( captures, _) = infer. closure_info ( & c) ;
222
+ let parent_subst = ClosureSubst ( subst) . parent_subst ( ) ;
223
+ captures
224
+ . get ( f)
225
+ . expect ( "broken closure field" )
226
+ . ty
227
+ . clone ( )
228
+ . substitute ( Interner , parent_subst)
229
+ } ,
230
+ body. owner . module ( db. upcast ( ) ) . krate ( ) ,
231
+ ) ;
216
232
}
217
233
if is_part_of {
218
234
ProjectionCase :: DirectPart
@@ -300,7 +316,10 @@ fn ever_initialized_map(body: &MirBody) -> ArenaMap<BasicBlockId, ArenaMap<Local
300
316
result
301
317
}
302
318
303
- fn mutability_of_locals ( body : & MirBody ) -> ArenaMap < LocalId , MutabilityReason > {
319
+ fn mutability_of_locals (
320
+ db : & dyn HirDatabase ,
321
+ body : & MirBody ,
322
+ ) -> ArenaMap < LocalId , MutabilityReason > {
304
323
let mut result: ArenaMap < LocalId , MutabilityReason > =
305
324
body. locals . iter ( ) . map ( |x| ( x. 0 , MutabilityReason :: Not ) ) . collect ( ) ;
306
325
let mut push_mut_span = |local, span| match & mut result[ local] {
@@ -313,7 +332,7 @@ fn mutability_of_locals(body: &MirBody) -> ArenaMap<LocalId, MutabilityReason> {
313
332
for statement in & block. statements {
314
333
match & statement. kind {
315
334
StatementKind :: Assign ( place, value) => {
316
- match place_case ( place) {
335
+ match place_case ( db , body , place) {
317
336
ProjectionCase :: Direct => {
318
337
if ever_init_map. get ( place. local ) . copied ( ) . unwrap_or_default ( ) {
319
338
push_mut_span ( place. local , statement. span ) ;
@@ -328,7 +347,7 @@ fn mutability_of_locals(body: &MirBody) -> ArenaMap<LocalId, MutabilityReason> {
328
347
ProjectionCase :: Indirect => ( ) ,
329
348
}
330
349
if let Rvalue :: Ref ( BorrowKind :: Mut { .. } , p) = value {
331
- if is_place_direct ( p ) {
350
+ if place_case ( db , body , p ) != ProjectionCase :: Indirect {
332
351
push_mut_span ( p. local , statement. span ) ;
333
352
}
334
353
}
0 commit comments