@@ -78,7 +78,7 @@ pub fn borrowck_query(
7878 . map ( |body| {
7979 let body = body?;
8080 Ok ( BorrowckResult {
81- mutability_of_locals : mutability_of_locals ( & body) ,
81+ mutability_of_locals : mutability_of_locals ( db , & body) ,
8282 moved_out_of_ref : moved_out_of_ref ( db, & body) ,
8383 mir_body : body,
8484 } )
@@ -186,10 +186,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
186186 result
187187}
188188
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 ) ]
193190enum ProjectionCase {
194191 /// Projection is a local
195192 Direct ,
@@ -199,12 +196,14 @@ enum ProjectionCase {
199196 Indirect ,
200197}
201198
202- fn place_case ( lvalue : & Place ) -> ProjectionCase {
199+ fn place_case ( db : & dyn HirDatabase , body : & MirBody , lvalue : & Place ) -> ProjectionCase {
203200 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 ( ) {
205203 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 { .. }
208207 | ProjectionElem :: Subslice { .. }
209208 | ProjectionElem :: Field ( _)
210209 | ProjectionElem :: TupleOrClosureField ( _)
@@ -213,6 +212,23 @@ fn place_case(lvalue: &Place) -> ProjectionCase {
213212 }
214213 ProjectionElem :: OpaqueCast ( _) => ( ) ,
215214 }
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+ ) ;
216232 }
217233 if is_part_of {
218234 ProjectionCase :: DirectPart
@@ -300,7 +316,10 @@ fn ever_initialized_map(body: &MirBody) -> ArenaMap<BasicBlockId, ArenaMap<Local
300316 result
301317}
302318
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 > {
304323 let mut result: ArenaMap < LocalId , MutabilityReason > =
305324 body. locals . iter ( ) . map ( |x| ( x. 0 , MutabilityReason :: Not ) ) . collect ( ) ;
306325 let mut push_mut_span = |local, span| match & mut result[ local] {
@@ -313,7 +332,7 @@ fn mutability_of_locals(body: &MirBody) -> ArenaMap<LocalId, MutabilityReason> {
313332 for statement in & block. statements {
314333 match & statement. kind {
315334 StatementKind :: Assign ( place, value) => {
316- match place_case ( place) {
335+ match place_case ( db , body , place) {
317336 ProjectionCase :: Direct => {
318337 if ever_init_map. get ( place. local ) . copied ( ) . unwrap_or_default ( ) {
319338 push_mut_span ( place. local , statement. span ) ;
@@ -328,7 +347,7 @@ fn mutability_of_locals(body: &MirBody) -> ArenaMap<LocalId, MutabilityReason> {
328347 ProjectionCase :: Indirect => ( ) ,
329348 }
330349 if let Rvalue :: Ref ( BorrowKind :: Mut { .. } , p) = value {
331- if is_place_direct ( p ) {
350+ if place_case ( db , body , p ) != ProjectionCase :: Indirect {
332351 push_mut_span ( p. local , statement. span ) ;
333352 }
334353 }
0 commit comments