@@ -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 ( ) ) {
@@ -540,6 +538,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
540538 PlaceRef { local, projection : [ ProjectionElem :: Deref ] }
541539 if local == ty:: CAPTURE_STRUCT_LOCAL && !self . upvars . is_empty ( ) =>
542540 {
541+ self . point_at_binding_outside_closure ( & mut err, local, access_place) ;
543542 self . expected_fn_found_fn_mut_call ( & mut err, span, act) ;
544543 }
545544
@@ -958,6 +957,50 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
958957 }
959958 }
960959
960+ /// When modifying a binding from inside of an `Fn` closure, point at the binding definition.
961+ fn point_at_binding_outside_closure (
962+ & self ,
963+ err : & mut Diag < ' _ > ,
964+ local : Local ,
965+ access_place : Place < ' tcx > ,
966+ ) {
967+ let place = access_place. as_ref ( ) ;
968+ for ( index, elem) in place. projection . into_iter ( ) . enumerate ( ) {
969+ if let ProjectionElem :: Deref = elem {
970+ if index == 0 {
971+ if self . body . local_decls [ local] . is_ref_for_guard ( ) {
972+ continue ;
973+ }
974+ if let LocalInfo :: StaticRef { .. } = * self . body . local_decls [ local] . local_info ( )
975+ {
976+ continue ;
977+ }
978+ }
979+ if let Some ( field) = self . is_upvar_field_projection ( PlaceRef {
980+ local,
981+ projection : place. projection . split_at ( index + 1 ) . 0 ,
982+ } ) {
983+ let var_index = field. index ( ) ;
984+ let upvar = self . upvars [ var_index] ;
985+ if let Some ( hir_id) = upvar. info . capture_kind_expr_id {
986+ let node = self . infcx . tcx . hir_node ( hir_id) ;
987+ if let hir:: Node :: Expr ( expr) = node
988+ && let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
989+ && let hir:: def:: Res :: Local ( hir_id) = path. res
990+ && let hir:: Node :: Pat ( pat) = self . infcx . tcx . hir_node ( hir_id)
991+ {
992+ let name = upvar. to_string ( self . infcx . tcx ) ;
993+ err. span_label (
994+ pat. span ,
995+ format ! ( "`{name}` declared here, outside the closure" ) ,
996+ ) ;
997+ break ;
998+ }
999+ }
1000+ }
1001+ }
1002+ }
1003+ }
9611004 /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
9621005 fn expected_fn_found_fn_mut_call ( & self , err : & mut Diag < ' _ > , sp : Span , act : & str ) {
9631006 err. span_label ( sp, format ! ( "cannot {act}" ) ) ;
@@ -970,6 +1013,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
9701013 let def_id = tcx. hir_enclosing_body_owner ( fn_call_id) ;
9711014 let mut look_at_return = true ;
9721015
1016+ err. span_label ( closure_span, "in this closure" ) ;
9731017 // If the HIR node is a function or method call, get the DefId
9741018 // of the callee function or method, the span, and args of the call expr
9751019 let get_call_details = || {
@@ -1040,7 +1084,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
10401084 if let Some ( span) = arg {
10411085 err. span_label ( span, "change this to accept `FnMut` instead of `Fn`" ) ;
10421086 err. span_label ( call_span, "expects `Fn` instead of `FnMut`" ) ;
1043- err. span_label ( closure_span, "in this closure" ) ;
10441087 look_at_return = false ;
10451088 }
10461089 }
@@ -1067,7 +1110,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
10671110 sig. decl . output . span ( ) ,
10681111 "change this to return `FnMut` instead of `Fn`" ,
10691112 ) ;
1070- err. span_label ( closure_span, "in this closure" ) ;
10711113 }
10721114 _ => { }
10731115 }
0 commit comments