@@ -150,8 +150,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
150150 }
151151 }
152152 }
153- PlaceRef { local : _ , projection : [ proj_base @ .., ProjectionElem :: Deref ] } => {
154- if the_place_err . local == ty:: CAPTURE_STRUCT_LOCAL
153+ PlaceRef { local, projection : [ proj_base @ .., ProjectionElem :: Deref ] } => {
154+ if local == ty:: CAPTURE_STRUCT_LOCAL
155155 && proj_base. is_empty ( )
156156 && !self . upvars . is_empty ( )
157157 {
@@ -165,10 +165,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
165165 ", as `Fn` closures cannot mutate their captured variables" . to_string ( )
166166 }
167167 } else {
168- let source = self . borrowed_content_source ( PlaceRef {
169- local : the_place_err. local ,
170- projection : proj_base,
171- } ) ;
168+ let source =
169+ self . borrowed_content_source ( PlaceRef { local, projection : proj_base } ) ;
172170 let pointer_type = source. describe_for_immutable_place ( self . infcx . tcx ) ;
173171 opt_source = Some ( source) ;
174172 if let Some ( desc) = self . describe_place ( access_place. as_ref ( ) ) {
@@ -532,6 +530,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
532530 PlaceRef { local, projection : [ ProjectionElem :: Deref ] }
533531 if local == ty:: CAPTURE_STRUCT_LOCAL && !self . upvars . is_empty ( ) =>
534532 {
533+ self . point_at_binding_outside_closure ( & mut err, local, access_place) ;
535534 self . expected_fn_found_fn_mut_call ( & mut err, span, act) ;
536535 }
537536
@@ -950,6 +949,50 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
950949 }
951950 }
952951
952+ /// When modifying a binding from inside of an `Fn` closure, point at the binding definition.
953+ fn point_at_binding_outside_closure (
954+ & self ,
955+ err : & mut Diag < ' _ > ,
956+ local : Local ,
957+ access_place : Place < ' tcx > ,
958+ ) {
959+ let place = access_place. as_ref ( ) ;
960+ for ( index, elem) in place. projection . into_iter ( ) . enumerate ( ) {
961+ if let ProjectionElem :: Deref = elem {
962+ if index == 0 {
963+ if self . body . local_decls [ local] . is_ref_for_guard ( ) {
964+ continue ;
965+ }
966+ if let LocalInfo :: StaticRef { .. } = * self . body . local_decls [ local] . local_info ( )
967+ {
968+ continue ;
969+ }
970+ }
971+ if let Some ( field) = self . is_upvar_field_projection ( PlaceRef {
972+ local,
973+ projection : place. projection . split_at ( index + 1 ) . 0 ,
974+ } ) {
975+ let var_index = field. index ( ) ;
976+ let upvar = self . upvars [ var_index] ;
977+ if let Some ( hir_id) = upvar. info . capture_kind_expr_id {
978+ let node = self . infcx . tcx . hir_node ( hir_id) ;
979+ if let hir:: Node :: Expr ( expr) = node
980+ && let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
981+ && let hir:: def:: Res :: Local ( hir_id) = path. res
982+ && let hir:: Node :: Pat ( pat) = self . infcx . tcx . hir_node ( hir_id)
983+ {
984+ let name = upvar. to_string ( self . infcx . tcx ) ;
985+ err. span_label (
986+ pat. span ,
987+ format ! ( "`{name}` declared here, outside the closure" ) ,
988+ ) ;
989+ break ;
990+ }
991+ }
992+ }
993+ }
994+ }
995+ }
953996 /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
954997 fn expected_fn_found_fn_mut_call ( & self , err : & mut Diag < ' _ > , sp : Span , act : & str ) {
955998 err. span_label ( sp, format ! ( "cannot {act}" ) ) ;
@@ -962,6 +1005,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
9621005 let def_id = tcx. hir_enclosing_body_owner ( fn_call_id) ;
9631006 let mut look_at_return = true ;
9641007
1008+ err. span_label ( closure_span, "in this closure" ) ;
9651009 // If the HIR node is a function or method call, get the DefId
9661010 // of the callee function or method, the span, and args of the call expr
9671011 let get_call_details = || {
@@ -1032,7 +1076,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
10321076 if let Some ( span) = arg {
10331077 err. span_label ( span, "change this to accept `FnMut` instead of `Fn`" ) ;
10341078 err. span_label ( call_span, "expects `Fn` instead of `FnMut`" ) ;
1035- err. span_label ( closure_span, "in this closure" ) ;
10361079 look_at_return = false ;
10371080 }
10381081 }
@@ -1059,7 +1102,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
10591102 sig. decl . output . span ( ) ,
10601103 "change this to return `FnMut` instead of `Fn`" ,
10611104 ) ;
1062- err. span_label ( closure_span, "in this closure" ) ;
10631105 }
10641106 _ => { }
10651107 }
0 commit comments