about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2025-08-07 21:09:42 +0000
committerEsteban Küber <esteban@kuber.com.ar>2025-08-10 19:22:49 +0000
commit2484e189bfbc3decc2aa8480ce249dd84f6d2f9c (patch)
tree3c1f98ed5903f07a6bdd09285e74be89a1534896
parent1aa5668d20d53976860d141a66aa727e425e1079 (diff)
downloadrust-2484e189bfbc3decc2aa8480ce249dd84f6d2f9c.tar.gz
rust-2484e189bfbc3decc2aa8480ce249dd84f6d2f9c.zip
Add support for method calls
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs74
-rw-r--r--tests/ui/suggestions/dont-suggest-ref/move-into-closure.rs140
-rw-r--r--tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr566
3 files changed, 725 insertions, 55 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index b24cb012d2b..5adbaca7e11 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -9,6 +9,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
+use rustc_span::def_id::DefId;
 use rustc_span::{BytePos, DUMMY_SP, ExpnKind, MacroKind, Span};
 use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -507,38 +508,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 );
 
                 let closure_span = tcx.def_span(def_id);
-                let mut clause_span = DUMMY_SP;
-                let typck_result = self.infcx.tcx.typeck(self.mir_def_id());
-                if let Some(closure_def_id) = def_id.as_local()
-                    && let hir::Node::Expr(expr) = tcx.hir_node_by_def_id(closure_def_id)
-                    && let hir::Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id)
-                    && let hir::ExprKind::Call(callee, _) = parent.kind
-                    && let Some(ty) = typck_result.node_type_opt(callee.hir_id)
-                    && let ty::FnDef(fn_def_id, args) = ty.kind()
-                    && let predicates = tcx.predicates_of(fn_def_id).instantiate(tcx, args)
-                    && let Some((_, span)) =
-                        predicates.predicates.iter().zip(predicates.spans.iter()).find(
-                            |(pred, _)| match pred.as_trait_clause() {
-                                Some(clause)
-                                    if let ty::Closure(clause_closure_def_id, _) =
-                                        clause.self_ty().skip_binder().kind()
-                                        && clause_closure_def_id == def_id
-                                        && (tcx.lang_items().fn_mut_trait()
-                                            == Some(clause.def_id())
-                                            || tcx.lang_items().fn_trait()
-                                                == Some(clause.def_id())) =>
-                                {
-                                    // Found `<TyOfCapturingClosure as FnMut>`
-                                    true
-                                }
-                                _ => false,
-                            },
-                        )
-                {
-                    // We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
-                    // could be changed to `FnOnce()` to avoid the move error.
-                    clause_span = *span;
-                }
 
                 self.cannot_move_out_of(span, &place_description)
                     .with_span_label(upvar_span, "captured outer variable")
@@ -547,7 +516,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         format!("captured by this `{closure_kind}` closure"),
                     )
                     .with_span_help(
-                        clause_span,
+                        self.get_closure_bound_clause_span(*def_id),
                         "`Fn` and `FnMut` closures require captured values to be able to be \
                          consumed multiple times, but an `FnOnce` consume them only once",
                     )
@@ -599,6 +568,45 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         err
     }
 
+    fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span {
+        let tcx = self.infcx.tcx;
+        let typeck_result = tcx.typeck(self.mir_def_id());
+        let Some(closure_def_id) = def_id.as_local() else { return DUMMY_SP };
+        let hir::Node::Expr(expr) = tcx.hir_node_by_def_id(closure_def_id) else { return DUMMY_SP };
+        let hir::Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id) else { return DUMMY_SP };
+        let predicates = match parent.kind {
+            hir::ExprKind::Call(callee, _) => {
+                let Some(ty) = typeck_result.node_type_opt(callee.hir_id) else { return DUMMY_SP };
+                let ty::FnDef(fn_def_id, args) = ty.kind() else { return DUMMY_SP };
+                tcx.predicates_of(fn_def_id).instantiate(tcx, args)
+            }
+            hir::ExprKind::MethodCall(..) => {
+                let Some((_, method)) = typeck_result.type_dependent_def(parent.hir_id) else {
+                    return DUMMY_SP;
+                };
+                let args = typeck_result.node_args(parent.hir_id);
+                tcx.predicates_of(method).instantiate(tcx, args)
+            }
+            _ => return DUMMY_SP,
+        };
+        for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
+            tracing::info!(?pred);
+            tracing::info!(?span);
+            if let Some(clause) = pred.as_trait_clause()
+                && let ty::Closure(clause_closure_def_id, _) = clause.self_ty().skip_binder().kind()
+                && *clause_closure_def_id == def_id
+                && (tcx.lang_items().fn_mut_trait() == Some(clause.def_id())
+                    || tcx.lang_items().fn_trait() == Some(clause.def_id()))
+            {
+                // Found `<TyOfCapturingClosure as FnMut>`
+                // We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
+                // could be changed to `FnOnce()` to avoid the move error.
+                return *span;
+            }
+        }
+        DUMMY_SP
+    }
+
     fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
         match error {
             GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
diff --git a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.rs b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.rs
index 0154810f564..34088f219b2 100644
--- a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.rs
+++ b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.rs
@@ -35,6 +35,32 @@ fn consume_fnmut<F: FnMut()>(_f: F) { }
 //~| HELP `Fn` and `FnMut` closures
 //~| HELP `Fn` and `FnMut` closures
 
+trait T {
+    fn consume_fn<F: Fn()>(_f: F) { }
+    //~^ HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+    //~^ HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+}
+impl T for () {}
+
 pub fn main() { }
 
 fn move_into_fn() {
@@ -94,6 +120,120 @@ fn move_into_fn() {
     });
 }
 
+fn move_into_assoc_fn() {
+    let e = Either::One(X(Y));
+    let mut em = Either::One(X(Y));
+
+    let x = X(Y);
+
+    // move into Fn
+
+    <() as T>::consume_fn(|| {
+        let X(_t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        if let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        while let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(_t)
+            | Either::Two(_t) => (),
+        }
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(_t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+
+        let X(mut _t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        if let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        while let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(mut _t)
+            | Either::Two(mut _t) => (),
+        }
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(mut _t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+    });
+}
+
+fn move_into_method() {
+    let e = Either::One(X(Y));
+    let mut em = Either::One(X(Y));
+
+    let x = X(Y);
+
+    // move into Fn
+
+    ().method_consume_fn(|| {
+        let X(_t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        if let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        while let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(_t)
+            | Either::Two(_t) => (),
+        }
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(_t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+
+        let X(mut _t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        if let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        while let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(mut _t)
+            | Either::Two(mut _t) => (),
+        }
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(mut _t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+    });
+}
+
 fn move_into_fnmut() {
     let e = Either::One(X(Y));
     let mut em = Either::One(X(Y));
diff --git a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
index d9ed25983d6..132a31c8f7c 100644
--- a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
+++ b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:49:21
+  --> $DIR/move-into-closure.rs:75:21
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -23,7 +23,7 @@ LL |         let X(_t) = &x;
    |                     +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:52:34
+  --> $DIR/move-into-closure.rs:78:34
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -48,7 +48,7 @@ LL |         if let Either::One(_t) = &e { }
    |                                  +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:55:37
+  --> $DIR/move-into-closure.rs:81:37
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -73,7 +73,7 @@ LL |         while let Either::One(_t) = &e { }
    |                                     +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:58:15
+  --> $DIR/move-into-closure.rs:84:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -101,7 +101,7 @@ LL |         match &e {
    |               +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:64:15
+  --> $DIR/move-into-closure.rs:90:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -129,7 +129,7 @@ LL |         match &e {
    |               +
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:72:25
+  --> $DIR/move-into-closure.rs:98:25
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -154,7 +154,7 @@ LL |         let X(mut _t) = &x;
    |                         +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:75:38
+  --> $DIR/move-into-closure.rs:101:38
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -179,7 +179,7 @@ LL |         if let Either::One(mut _t) = &em { }
    |                                      +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:78:41
+  --> $DIR/move-into-closure.rs:104:41
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -204,7 +204,7 @@ LL |         while let Either::One(mut _t) = &em { }
    |                                         +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:81:15
+  --> $DIR/move-into-closure.rs:107:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -232,7 +232,7 @@ LL |         match &em {
    |               +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:87:15
+  --> $DIR/move-into-closure.rs:113:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -259,8 +259,530 @@ help: consider borrowing here
 LL |         match &em {
    |               +
 
+error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:132:21
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+LL |         let X(_t) = x;
+   |               --    ^
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         let X(_t) = &x;
+   |                     +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:135:34
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         if let Either::One(_t) = e { }
+   |                            --    ^
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         if let Either::One(_t) = &e { }
+   |                                  +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:138:37
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         while let Either::One(_t) = e { }
+   |                               --    ^
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         while let Either::One(_t) = &e { }
+   |                                     +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:141:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         match e {
+   |               ^
+...
+LL |             Either::One(_t)
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         match &e {
+   |               +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:147:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         match e {
+   |               ^
+...
+LL |             Either::One(_t) => (),
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         match &e {
+   |               +
+
+error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:155:25
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         let X(mut _t) = x;
+   |               ------    ^
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         let X(mut _t) = &x;
+   |                         +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:158:38
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         if let Either::One(mut _t) = em { }
+   |                            ------    ^^
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         if let Either::One(mut _t) = &em { }
+   |                                      +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:161:41
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         while let Either::One(mut _t) = em { }
+   |                               ------    ^^
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         while let Either::One(mut _t) = &em { }
+   |                                         +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:164:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         match em {
+   |               ^^
+...
+LL |             Either::One(mut _t)
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         match &em {
+   |               +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:170:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         match em {
+   |               ^^
+...
+LL |             Either::One(mut _t) => (),
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         match &em {
+   |               +
+
+error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:189:21
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+LL |         let X(_t) = x;
+   |               --    ^
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         let X(_t) = &x;
+   |                     +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:192:34
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         if let Either::One(_t) = e { }
+   |                            --    ^
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         if let Either::One(_t) = &e { }
+   |                                  +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:195:37
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         while let Either::One(_t) = e { }
+   |                               --    ^
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         while let Either::One(_t) = &e { }
+   |                                     +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:198:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         match e {
+   |               ^
+...
+LL |             Either::One(_t)
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         match &e {
+   |               +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:204:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         match e {
+   |               ^
+...
+LL |             Either::One(_t) => (),
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         match &e {
+   |               +
+
+error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:212:25
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         let X(mut _t) = x;
+   |               ------    ^
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         let X(mut _t) = &x;
+   |                         +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:215:38
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         if let Either::One(mut _t) = em { }
+   |                            ------    ^^
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         if let Either::One(mut _t) = &em { }
+   |                                      +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:218:41
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         while let Either::One(mut _t) = em { }
+   |                               ------    ^^
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         while let Either::One(mut _t) = &em { }
+   |                                         +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:221:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         match em {
+   |               ^^
+...
+LL |             Either::One(mut _t)
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         match &em {
+   |               +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:227:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         match em {
+   |               ^^
+...
+LL |             Either::One(mut _t) => (),
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         match &em {
+   |               +
+
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:106:21
+  --> $DIR/move-into-closure.rs:246:21
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -284,7 +806,7 @@ LL |         let X(_t) = &x;
    |                     +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:109:34
+  --> $DIR/move-into-closure.rs:249:34
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -309,7 +831,7 @@ LL |         if let Either::One(_t) = &e { }
    |                                  +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:112:37
+  --> $DIR/move-into-closure.rs:252:37
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -334,7 +856,7 @@ LL |         while let Either::One(_t) = &e { }
    |                                     +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:115:15
+  --> $DIR/move-into-closure.rs:255:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -362,7 +884,7 @@ LL |         match &e {
    |               +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:121:15
+  --> $DIR/move-into-closure.rs:261:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -390,7 +912,7 @@ LL |         match &e {
    |               +
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:129:25
+  --> $DIR/move-into-closure.rs:269:25
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -415,7 +937,7 @@ LL |         let X(mut _t) = &x;
    |                         +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:132:38
+  --> $DIR/move-into-closure.rs:272:38
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -440,7 +962,7 @@ LL |         if let Either::One(mut _t) = &em { }
    |                                      +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:135:41
+  --> $DIR/move-into-closure.rs:275:41
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -465,7 +987,7 @@ LL |         while let Either::One(mut _t) = &em { }
    |                                         +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:138:15
+  --> $DIR/move-into-closure.rs:278:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -493,7 +1015,7 @@ LL |         match &em {
    |               +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:144:15
+  --> $DIR/move-into-closure.rs:284:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -521,7 +1043,7 @@ LL |         match &em {
    |               +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:151:15
+  --> $DIR/move-into-closure.rs:291:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -548,6 +1070,6 @@ help: consider borrowing here
 LL |         match &em {
    |               +
 
-error: aborting due to 21 previous errors
+error: aborting due to 41 previous errors
 
 For more information about this error, try `rustc --explain E0507`.