about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-11-21 04:20:18 +0000
committerMichael Goulet <michael@errs.io>2023-11-21 18:35:47 +0000
commit128feaa2b40d063a834030d3ff9410c9327c5286 (patch)
tree5068d61a731ce5dca2611a26baa7f1d4c3b90fdf
parent93298ee0dd938c0fece0ee5dbafe851e54dd6386 (diff)
downloadrust-128feaa2b40d063a834030d3ff9410c9327c5286.tar.gz
rust-128feaa2b40d063a834030d3ff9410c9327c5286.zip
Restore closure-kind error messages
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs44
-rw-r--r--tests/ui/closure_context/issue-26046-fn-mut.stderr16
-rw-r--r--tests/ui/closure_context/issue-26046-fn-once.stderr16
-rw-r--r--tests/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr16
-rw-r--r--tests/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr16
-rw-r--r--tests/ui/closures/closure-wrong-kind.stderr14
-rw-r--r--tests/ui/issues/issue-34349.stderr16
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr53
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr15
10 files changed, 139 insertions, 73 deletions
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 956d097a5b2..d6c7a24476f 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -906,12 +906,14 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
     }
 
-    pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
+    pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool
     where
         T: at::ToTrace<'tcx>,
     {
         let origin = &ObligationCause::dummy();
-        self.probe(|_| self.at(origin, param_env).sub(DefineOpaqueTypes::No, a, b).is_ok())
+        self.probe(|_| {
+            self.at(origin, param_env).sub(DefineOpaqueTypes::No, expected, actual).is_ok()
+        })
     }
 
     pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 5f642ca9a79..fa24b2a4055 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -98,6 +98,12 @@ pub trait TypeErrCtxtExt<'tcx> {
         error: &SelectionError<'tcx>,
     );
 
+    fn emit_specialized_closure_kind_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Option<ErrorGuaranteed>;
+
     fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool;
 
     fn report_const_param_not_wf(
@@ -411,6 +417,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
                         let trait_predicate = bound_predicate.rebind(trait_predicate);
                         let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+                        let trait_ref = trait_predicate.to_poly_trait_ref();
+
+                        if let Some(_guar) = self.emit_specialized_closure_kind_error(&obligation, trait_ref) {
+                            return;
+                        }
 
                         // FIXME(effects)
                         let predicate_is_const = false;
@@ -425,7 +436,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             // reported on the binding definition (#56607).
                             return;
                         }
-                        let trait_ref = trait_predicate.to_poly_trait_ref();
                         let (post_message, pre_message, type_def, file_note) = self
                             .get_parent_trait_ref(obligation.cause.code())
                             .map(|(t, s)| {
@@ -922,6 +932,38 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         err.emit();
     }
 
+    fn emit_specialized_closure_kind_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Option<ErrorGuaranteed> {
+        if let ty::Closure(closure_def_id, closure_args) = *trait_ref.self_ty().skip_binder().kind()
+            && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
+            && let Some(found_kind) = self.closure_kind(closure_args)
+            && !found_kind.extends(expected_kind)
+            && let sig = closure_args.as_closure().sig()
+            && self.can_sub(
+                obligation.param_env,
+                trait_ref,
+                sig.map_bound(|sig| {
+                    ty::TraitRef::new(
+                        self.tcx,
+                        trait_ref.def_id(),
+                        [trait_ref.self_ty().skip_binder(), sig.inputs()[0]],
+                    )
+                }),
+            )
+        {
+            let mut err =
+                self.report_closure_error(&obligation, closure_def_id, found_kind, expected_kind);
+            self.note_obligation_cause(&mut err, &obligation);
+            self.point_at_returns_when_relevant(&mut err, &obligation);
+            Some(err.emit())
+        } else {
+            None
+        }
+    }
+
     fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool {
         if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
             obligation.cause.code()
diff --git a/tests/ui/closure_context/issue-26046-fn-mut.stderr b/tests/ui/closure_context/issue-26046-fn-mut.stderr
index 5f0b6fd451c..eeb40945242 100644
--- a/tests/ui/closure_context/issue-26046-fn-mut.stderr
+++ b/tests/ui/closure_context/issue-26046-fn-mut.stderr
@@ -1,14 +1,16 @@
-error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}`
-  --> $DIR/issue-26046-fn-mut.rs:8:5
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
+  --> $DIR/issue-26046-fn-mut.rs:4:19
    |
+LL |     let closure = || {
+   |                   ^^ this closure implements `FnMut`, not `Fn`
+LL |         num += 1;
+   |         --- closure is `FnMut` because it mutates the variable `num` here
+...
 LL |     Box::new(closure)
-   |     ^^^^^^^^^^^^^^^^^ expected an `Fn()` closure, found `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}`
+   |     ----------------- the requirement to implement `Fn` derives from here
    |
-   = help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}`
-   = note: wrap the `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}` in a closure with no arguments: `|| { /* code */ }`
-   = note: `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}` implements `FnMut`, but it must implement `Fn`, which is more general
    = note: required for the cast from `Box<{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}>` to `Box<(dyn Fn() + 'static)>`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/closure_context/issue-26046-fn-once.stderr b/tests/ui/closure_context/issue-26046-fn-once.stderr
index da3dcf3e3af..24773a1d7e3 100644
--- a/tests/ui/closure_context/issue-26046-fn-once.stderr
+++ b/tests/ui/closure_context/issue-26046-fn-once.stderr
@@ -1,14 +1,16 @@
-error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}`
-  --> $DIR/issue-26046-fn-once.rs:8:5
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/issue-26046-fn-once.rs:4:19
    |
+LL |     let closure = move || {
+   |                   ^^^^^^^ this closure implements `FnOnce`, not `Fn`
+LL |         vec
+   |         --- closure is `FnOnce` because it moves the variable `vec` out of its environment
+...
 LL |     Box::new(closure)
-   |     ^^^^^^^^^^^^^^^^^ expected an `Fn()` closure, found `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}`
+   |     ----------------- the requirement to implement `Fn` derives from here
    |
-   = help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}`
-   = note: wrap the `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}` in a closure with no arguments: `|| { /* code */ }`
-   = note: `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}` implements `FnOnce`, but it must implement `Fn`, which is more general
    = note: required for the cast from `Box<{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}>` to `Box<(dyn Fn() -> Vec<u8> + 'static)>`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr
index 189f08c12e9..309c63e5293 100644
--- a/tests/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr
+++ b/tests/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr
@@ -1,14 +1,16 @@
-error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}`
-  --> $DIR/closure-origin-array-diagnostics.rs:12:15
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/closure-origin-array-diagnostics.rs:9:13
    |
+LL |     let c = || {
+   |             ^^ this closure implements `FnOnce`, not `Fn`
+LL |         let [_, _s] = s;
+   |                       - closure is `FnOnce` because it moves the variable `s` out of its environment
+LL |     };
 LL |     expect_fn(c);
-   |     --------- ^ expected an `Fn()` closure, found `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}`
+   |     --------- - the requirement to implement `Fn` derives from here
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}`
-   = note: wrap the `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}` in a closure with no arguments: `|| { /* code */ }`
-   = note: `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}` implements `FnOnce`, but it must implement `Fn`, which is more general
 note: required by a bound in `expect_fn`
   --> $DIR/closure-origin-array-diagnostics.rs:5:17
    |
@@ -17,4 +19,4 @@ LL | fn expect_fn<F: Fn()>(_f: F) {}
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr
index 75c49d312a5..3e77635f9e0 100644
--- a/tests/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr
+++ b/tests/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr
@@ -1,14 +1,16 @@
-error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}`
-  --> $DIR/closure-origin-tuple-diagnostics.rs:12:15
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/closure-origin-tuple-diagnostics.rs:9:13
    |
+LL |     let c = || {
+   |             ^^ this closure implements `FnOnce`, not `Fn`
+LL |         let s = s.1;
+   |                 --- closure is `FnOnce` because it moves the variable `s.1` out of its environment
+LL |     };
 LL |     expect_fn(c);
-   |     --------- ^ expected an `Fn()` closure, found `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}`
+   |     --------- - the requirement to implement `Fn` derives from here
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}`
-   = note: wrap the `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}` in a closure with no arguments: `|| { /* code */ }`
-   = note: `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}` implements `FnOnce`, but it must implement `Fn`, which is more general
 note: required by a bound in `expect_fn`
   --> $DIR/closure-origin-tuple-diagnostics.rs:5:17
    |
@@ -17,4 +19,4 @@ LL | fn expect_fn<F: Fn()>(_f: F) {}
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/closures/closure-wrong-kind.stderr b/tests/ui/closures/closure-wrong-kind.stderr
index c1c83014438..9ea55d764f3 100644
--- a/tests/ui/closures/closure-wrong-kind.stderr
+++ b/tests/ui/closures/closure-wrong-kind.stderr
@@ -1,13 +1,15 @@
-error[E0277]: expected a `Fn(u32)` closure, found `{closure@$DIR/closure-wrong-kind.rs:10:19: 10:22}`
-  --> $DIR/closure-wrong-kind.rs:11:9
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/closure-wrong-kind.rs:10:19
    |
+LL |     let closure = |_| foo(x);
+   |                   ^^^     - closure is `FnOnce` because it moves the variable `x` out of its environment
+   |                   |
+   |                   this closure implements `FnOnce`, not `Fn`
 LL |     bar(closure);
-   |     --- ^^^^^^^ expected an `Fn(u32)` closure, found `{closure@$DIR/closure-wrong-kind.rs:10:19: 10:22}`
+   |     --- ------- the requirement to implement `Fn` derives from here
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Fn<(u32,)>` is not implemented for closure `{closure@$DIR/closure-wrong-kind.rs:10:19: 10:22}`
-   = note: `{closure@$DIR/closure-wrong-kind.rs:10:19: 10:22}` implements `FnOnce`, but it must implement `Fn`, which is more general
 note: required by a bound in `bar`
   --> $DIR/closure-wrong-kind.rs:6:11
    |
@@ -16,4 +18,4 @@ LL | fn bar<T: Fn(u32)>(_: T) {}
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/issues/issue-34349.stderr b/tests/ui/issues/issue-34349.stderr
index 1235f44f4aa..8e9a16619f3 100644
--- a/tests/ui/issues/issue-34349.stderr
+++ b/tests/ui/issues/issue-34349.stderr
@@ -1,14 +1,16 @@
-error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/issue-34349.rs:16:17: 16:19}`
-  --> $DIR/issue-34349.rs:21:11
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
+  --> $DIR/issue-34349.rs:16:17
    |
+LL |     let diary = || {
+   |                 ^^ this closure implements `FnMut`, not `Fn`
+LL |         farewell.push_str("!!!");
+   |         -------- closure is `FnMut` because it mutates the variable `farewell` here
+...
 LL |     apply(diary);
-   |     ----- ^^^^^ expected an `Fn()` closure, found `{closure@$DIR/issue-34349.rs:16:17: 16:19}`
+   |     ----- ----- the requirement to implement `Fn` derives from here
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/issue-34349.rs:16:17: 16:19}`
-   = note: wrap the `{closure@$DIR/issue-34349.rs:16:17: 16:19}` in a closure with no arguments: `|| { /* code */ }`
-   = note: `{closure@$DIR/issue-34349.rs:16:17: 16:19}` implements `FnMut`, but it must implement `Fn`, which is more general
 note: required by a bound in `apply`
   --> $DIR/issue-34349.rs:11:32
    |
@@ -17,4 +19,4 @@ LL |     fn apply<F>(f: F) where F: Fn() {
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
index 9a8c8123fba..eba65a61803 100644
--- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
@@ -1,48 +1,57 @@
-error[E0277]: expected a `FnMut()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
-  --> $DIR/move-ref-patterns-closure-captures.rs:17:19
-   |
+error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
+  --> $DIR/move-ref-patterns-closure-captures.rs:9:14
+   |
+LL |     let c1 = || {
+   |              ^^ this closure implements `FnOnce`, not `FnMut`
+...
+LL |         drop::<U>(_x1);
+   |                   --- closure is `FnOnce` because it moves the variable `_x1` out of its environment
+...
 LL |     accept_fn_mut(&c1);
-   |     ------------- ^^^ expected an `FnMut()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
+   |     ------------- --- the requirement to implement `FnMut` derives from here
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `FnMut<()>` is not implemented for closure `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
-   = note: wrap the `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}` in a closure with no arguments: `|| { /* code */ }`
-   = note: `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}` implements `FnOnce`, but it must implement `FnMut`, which is more general
 note: required by a bound in `accept_fn_mut`
   --> $DIR/move-ref-patterns-closure-captures.rs:4:31
    |
 LL |     fn accept_fn_mut(_: &impl FnMut()) {}
    |                               ^^^^^^^ required by this bound in `accept_fn_mut`
 
-error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
-  --> $DIR/move-ref-patterns-closure-captures.rs:18:15
-   |
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/move-ref-patterns-closure-captures.rs:9:14
+   |
+LL |     let c1 = || {
+   |              ^^ this closure implements `FnOnce`, not `Fn`
+...
+LL |         drop::<U>(_x1);
+   |                   --- closure is `FnOnce` because it moves the variable `_x1` out of its environment
+...
 LL |     accept_fn(&c1);
-   |     --------- ^^^ expected an `Fn()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
+   |     --------- --- the requirement to implement `Fn` derives from here
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
-   = note: wrap the `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}` in a closure with no arguments: `|| { /* code */ }`
-   = note: `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}` implements `FnOnce`, but it must implement `Fn`, which is more general
 note: required by a bound in `accept_fn`
   --> $DIR/move-ref-patterns-closure-captures.rs:5:27
    |
 LL |     fn accept_fn(_: &impl Fn()) {}
    |                           ^^^^ required by this bound in `accept_fn`
 
-error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:20:14: 20:16}`
-  --> $DIR/move-ref-patterns-closure-captures.rs:26:15
-   |
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
+  --> $DIR/move-ref-patterns-closure-captures.rs:20:14
+   |
+LL |     let c2 = || {
+   |              ^^ this closure implements `FnMut`, not `Fn`
+...
+LL |         drop::<&mut U>(_x2);
+   |                        --- closure is `FnMut` because it mutates the variable `_x2` here
+...
 LL |     accept_fn(&c2);
-   |     --------- ^^^ expected an `Fn()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:20:14: 20:16}`
+   |     --------- --- the requirement to implement `Fn` derives from here
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/move-ref-patterns-closure-captures.rs:20:14: 20:16}`
-   = note: wrap the `{closure@$DIR/move-ref-patterns-closure-captures.rs:20:14: 20:16}` in a closure with no arguments: `|| { /* code */ }`
-   = note: `{closure@$DIR/move-ref-patterns-closure-captures.rs:20:14: 20:16}` implements `FnMut`, but it must implement `Fn`, which is more general
 note: required by a bound in `accept_fn`
   --> $DIR/move-ref-patterns-closure-captures.rs:5:27
    |
@@ -51,4 +60,4 @@ LL |     fn accept_fn(_: &impl Fn()) {}
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr
index 8a06d2f66bf..846a44ce4d7 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr
@@ -1,14 +1,15 @@
-error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13: 14:15}`
-  --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:15:9
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13
    |
+LL |     let c = || drop(y.0);
+   |             ^^      --- closure is `FnOnce` because it moves the variable `y` out of its environment
+   |             |
+   |             this closure implements `FnOnce`, not `Fn`
 LL |     foo(c);
-   |     --- ^ expected an `Fn()` closure, found `{closure@$DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13: 14:15}`
+   |     --- - the requirement to implement `Fn` derives from here
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13: 14:15}`
-   = note: wrap the `{closure@$DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13: 14:15}` in a closure with no arguments: `|| { /* code */ }`
-   = note: `{closure@$DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13: 14:15}` implements `FnOnce`, but it must implement `Fn`, which is more general
 note: required by a bound in `foo`
   --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:4:14
    |
@@ -19,4 +20,4 @@ LL |     where F: Fn()
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0525`.