@@ -115,10 +115,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
115115 fn append_to_grouped_errors (
116116 & self ,
117117 grouped_errors : & mut Vec < GroupedMoveError < ' tcx > > ,
118- error : MoveError < ' tcx > ,
118+ MoveError { place : original_path , location , kind } : MoveError < ' tcx > ,
119119 ) {
120- let MoveError { place : original_path, location, kind } = error;
121-
122120 // Note: that the only time we assign a place isn't a temporary
123121 // to a user variable is when initializing it.
124122 // If that ever stops being the case, then the ever initialized
@@ -251,54 +249,47 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
251249 }
252250
253251 fn report ( & mut self , error : GroupedMoveError < ' tcx > ) {
254- let ( mut err, err_span) = {
255- let ( span, use_spans, original_path, kind) = match error {
256- GroupedMoveError :: MovesFromPlace { span, original_path, ref kind, .. }
257- | GroupedMoveError :: MovesFromValue { span, original_path, ref kind, .. } => {
258- ( span, None , original_path, kind)
259- }
260- GroupedMoveError :: OtherIllegalMove { use_spans, original_path, ref kind } => {
261- ( use_spans. args_or_use ( ) , Some ( use_spans) , original_path, kind)
262- }
263- } ;
264- debug ! (
265- "report: original_path={:?} span={:?}, kind={:?} \
266- original_path.is_upvar_field_projection={:?}",
267- original_path,
268- span,
269- kind,
270- self . is_upvar_field_projection( original_path. as_ref( ) )
271- ) ;
272- if self . has_ambiguous_copy ( original_path. ty ( self . body , self . infcx . tcx ) . ty ) {
273- // If the type may implement Copy, skip the error.
274- // It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check
275- self . dcx ( ) . span_delayed_bug (
252+ let ( span, use_spans, original_path, kind) = match error {
253+ GroupedMoveError :: MovesFromPlace { span, original_path, ref kind, .. }
254+ | GroupedMoveError :: MovesFromValue { span, original_path, ref kind, .. } => {
255+ ( span, None , original_path, kind)
256+ }
257+ GroupedMoveError :: OtherIllegalMove { use_spans, original_path, ref kind } => {
258+ ( use_spans. args_or_use ( ) , Some ( use_spans) , original_path, kind)
259+ }
260+ } ;
261+ debug ! (
262+ "report: original_path={:?} span={:?}, kind={:?} \
263+ original_path.is_upvar_field_projection={:?}",
264+ original_path,
265+ span,
266+ kind,
267+ self . is_upvar_field_projection( original_path. as_ref( ) )
268+ ) ;
269+ if self . has_ambiguous_copy ( original_path. ty ( self . body , self . infcx . tcx ) . ty ) {
270+ // If the type may implement Copy, skip the error.
271+ // It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check
272+ self . dcx ( )
273+ . span_delayed_bug ( span, "Type may implement copy, but there is no other error." ) ;
274+ return ;
275+ }
276+ let mut err = match kind {
277+ & IllegalMoveOriginKind :: BorrowedContent { target_place } => self
278+ . report_cannot_move_from_borrowed_content (
279+ original_path,
280+ target_place,
276281 span,
277- "Type may implement copy, but there is no other error." ,
278- ) ;
279- return ;
282+ use_spans,
283+ ) ,
284+ & IllegalMoveOriginKind :: InteriorOfTypeWithDestructor { container_ty : ty } => {
285+ self . cannot_move_out_of_interior_of_drop ( span, ty)
286+ }
287+ & IllegalMoveOriginKind :: InteriorOfSliceOrArray { ty, is_index } => {
288+ self . cannot_move_out_of_interior_noncopy ( span, ty, Some ( is_index) )
280289 }
281- (
282- match kind {
283- & IllegalMoveOriginKind :: BorrowedContent { target_place } => self
284- . report_cannot_move_from_borrowed_content (
285- original_path,
286- target_place,
287- span,
288- use_spans,
289- ) ,
290- & IllegalMoveOriginKind :: InteriorOfTypeWithDestructor { container_ty : ty } => {
291- self . cannot_move_out_of_interior_of_drop ( span, ty)
292- }
293- & IllegalMoveOriginKind :: InteriorOfSliceOrArray { ty, is_index } => {
294- self . cannot_move_out_of_interior_noncopy ( span, ty, Some ( is_index) )
295- }
296- } ,
297- span,
298- )
299290 } ;
300291
301- self . add_move_hints ( error, & mut err, err_span ) ;
292+ self . add_move_hints ( error, & mut err, span ) ;
302293 self . buffer_error ( err) ;
303294 }
304295
@@ -482,7 +473,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
482473 self . cannot_move_out_of_interior_noncopy ( span, ty, None )
483474 }
484475 ty:: Closure ( def_id, closure_args)
485- if def_id. as_local ( ) == Some ( self . mir_def_id ( ) ) && upvar_field. is_some ( ) =>
476+ if def_id. as_local ( ) == Some ( self . mir_def_id ( ) )
477+ && let Some ( upvar_field) = upvar_field =>
486478 {
487479 let closure_kind_ty = closure_args. as_closure ( ) . kind_ty ( ) ;
488480 let closure_kind = match closure_kind_ty. to_opt_closure_kind ( ) {
@@ -495,7 +487,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
495487 let capture_description =
496488 format ! ( "captured variable in an `{closure_kind}` closure" ) ;
497489
498- let upvar = & self . upvars [ upvar_field. unwrap ( ) . index ( ) ] ;
490+ let upvar = & self . upvars [ upvar_field. index ( ) ] ;
499491 let upvar_hir_id = upvar. get_root_variable ( ) ;
500492 let upvar_name = upvar. to_string ( tcx) ;
501493 let upvar_span = tcx. hir_span ( upvar_hir_id) ;
@@ -604,8 +596,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
604596 self . add_move_error_details ( err, & binds_to) ;
605597 }
606598 // No binding. Nothing to suggest.
607- GroupedMoveError :: OtherIllegalMove { ref original_path, use_spans, .. } => {
608- let use_span = use_spans. var_or_use ( ) ;
599+ GroupedMoveError :: OtherIllegalMove {
600+ ref original_path, use_spans, ref kind, ..
601+ } => {
602+ let mut use_span = use_spans. var_or_use ( ) ;
609603 let place_ty = original_path. ty ( self . body , self . infcx . tcx ) . ty ;
610604 let place_desc = match self . describe_place ( original_path. as_ref ( ) ) {
611605 Some ( desc) => format ! ( "`{desc}`" ) ,
@@ -622,6 +616,39 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
622616 ) ;
623617 }
624618
619+ if let IllegalMoveOriginKind :: BorrowedContent { target_place } = & kind
620+ && let ty = target_place. ty ( self . body , self . infcx . tcx ) . ty
621+ && let ty:: Closure ( def_id, _) = ty. kind ( )
622+ && def_id. as_local ( ) == Some ( self . mir_def_id ( ) )
623+ && let Some ( upvar_field) = self
624+ . prefixes ( original_path. as_ref ( ) , PrefixSet :: All )
625+ . find_map ( |p| self . is_upvar_field_projection ( p) )
626+ && let upvar = & self . upvars [ upvar_field. index ( ) ]
627+ && let upvar_hir_id = upvar. get_root_variable ( )
628+ && let hir:: Node :: Param ( param) = self . infcx . tcx . parent_hir_node ( upvar_hir_id)
629+ {
630+ // Instead of pointing at the path where we access the value within a closure,
631+ // we point at the type on the parameter from the definition of the outer
632+ // function:
633+ //
634+ // error[E0507]: cannot move out of `foo`, a captured
635+ // variable in an `Fn` closure
636+ // --> file.rs:14:25
637+ // |
638+ // 13 | fn do_stuff(foo: Option<Foo>) {
639+ // | --- ----------- move occurs because `foo` has type
640+ // | | `Option<Foo>`, which does not implement
641+ // | | the `Copy` trait
642+ // | captured outer variable
643+ // 14 | require_fn_trait(|| async {
644+ // | -- ^^^^^ `foo` is moved here
645+ // | |
646+ // | captured by this `Fn` closure
647+ // 15 | if foo.map_or(false, |f| f.foo()) {
648+ // | --- variable moved due to use in coroutine
649+ use_span = param. ty_span ;
650+ }
651+
625652 err. subdiagnostic ( crate :: session_diagnostics:: TypeNoCopy :: Label {
626653 is_partial_move : false ,
627654 ty : place_ty,
0 commit comments