Skip to content

Commit 128feaa

Browse files
Restore closure-kind error messages
1 parent 93298ee commit 128feaa

File tree

10 files changed

+139
-73
lines changed

10 files changed

+139
-73
lines changed

compiler/rustc_infer/src/infer/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -906,12 +906,14 @@ impl<'tcx> InferCtxt<'tcx> {
906906
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
907907
}
908908

909-
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
909+
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool
910910
where
911911
T: at::ToTrace<'tcx>,
912912
{
913913
let origin = &ObligationCause::dummy();
914-
self.probe(|_| self.at(origin, param_env).sub(DefineOpaqueTypes::No, a, b).is_ok())
914+
self.probe(|_| {
915+
self.at(origin, param_env).sub(DefineOpaqueTypes::No, expected, actual).is_ok()
916+
})
915917
}
916918

917919
pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool

compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

+43-1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ pub trait TypeErrCtxtExt<'tcx> {
9898
error: &SelectionError<'tcx>,
9999
);
100100

101+
fn emit_specialized_closure_kind_error(
102+
&self,
103+
obligation: &PredicateObligation<'tcx>,
104+
trait_ref: ty::PolyTraitRef<'tcx>,
105+
) -> Option<ErrorGuaranteed>;
106+
101107
fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool;
102108

103109
fn report_const_param_not_wf(
@@ -411,6 +417,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
411417
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
412418
let trait_predicate = bound_predicate.rebind(trait_predicate);
413419
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
420+
let trait_ref = trait_predicate.to_poly_trait_ref();
421+
422+
if let Some(_guar) = self.emit_specialized_closure_kind_error(&obligation, trait_ref) {
423+
return;
424+
}
414425

415426
// FIXME(effects)
416427
let predicate_is_const = false;
@@ -425,7 +436,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
425436
// reported on the binding definition (#56607).
426437
return;
427438
}
428-
let trait_ref = trait_predicate.to_poly_trait_ref();
429439
let (post_message, pre_message, type_def, file_note) = self
430440
.get_parent_trait_ref(obligation.cause.code())
431441
.map(|(t, s)| {
@@ -922,6 +932,38 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
922932
err.emit();
923933
}
924934

935+
fn emit_specialized_closure_kind_error(
936+
&self,
937+
obligation: &PredicateObligation<'tcx>,
938+
trait_ref: ty::PolyTraitRef<'tcx>,
939+
) -> Option<ErrorGuaranteed> {
940+
if let ty::Closure(closure_def_id, closure_args) = *trait_ref.self_ty().skip_binder().kind()
941+
&& let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
942+
&& let Some(found_kind) = self.closure_kind(closure_args)
943+
&& !found_kind.extends(expected_kind)
944+
&& let sig = closure_args.as_closure().sig()
945+
&& self.can_sub(
946+
obligation.param_env,
947+
trait_ref,
948+
sig.map_bound(|sig| {
949+
ty::TraitRef::new(
950+
self.tcx,
951+
trait_ref.def_id(),
952+
[trait_ref.self_ty().skip_binder(), sig.inputs()[0]],
953+
)
954+
}),
955+
)
956+
{
957+
let mut err =
958+
self.report_closure_error(&obligation, closure_def_id, found_kind, expected_kind);
959+
self.note_obligation_cause(&mut err, &obligation);
960+
self.point_at_returns_when_relevant(&mut err, &obligation);
961+
Some(err.emit())
962+
} else {
963+
None
964+
}
965+
}
966+
925967
fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool {
926968
if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
927969
obligation.cause.code()
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}`
2-
--> $DIR/issue-26046-fn-mut.rs:8:5
1+
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
2+
--> $DIR/issue-26046-fn-mut.rs:4:19
33
|
4+
LL | let closure = || {
5+
| ^^ this closure implements `FnMut`, not `Fn`
6+
LL | num += 1;
7+
| --- closure is `FnMut` because it mutates the variable `num` here
8+
...
49
LL | Box::new(closure)
5-
| ^^^^^^^^^^^^^^^^^ expected an `Fn()` closure, found `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}`
10+
| ----------------- the requirement to implement `Fn` derives from here
611
|
7-
= help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}`
8-
= note: wrap the `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}` in a closure with no arguments: `|| { /* code */ }`
9-
= note: `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}` implements `FnMut`, but it must implement `Fn`, which is more general
1012
= note: required for the cast from `Box<{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}>` to `Box<(dyn Fn() + 'static)>`
1113

1214
error: aborting due to previous error
1315

14-
For more information about this error, try `rustc --explain E0277`.
16+
For more information about this error, try `rustc --explain E0525`.
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}`
2-
--> $DIR/issue-26046-fn-once.rs:8:5
1+
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
2+
--> $DIR/issue-26046-fn-once.rs:4:19
33
|
4+
LL | let closure = move || {
5+
| ^^^^^^^ this closure implements `FnOnce`, not `Fn`
6+
LL | vec
7+
| --- closure is `FnOnce` because it moves the variable `vec` out of its environment
8+
...
49
LL | Box::new(closure)
5-
| ^^^^^^^^^^^^^^^^^ expected an `Fn()` closure, found `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}`
10+
| ----------------- the requirement to implement `Fn` derives from here
611
|
7-
= help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}`
8-
= note: wrap the `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}` in a closure with no arguments: `|| { /* code */ }`
9-
= note: `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}` implements `FnOnce`, but it must implement `Fn`, which is more general
1012
= 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)>`
1113

1214
error: aborting due to previous error
1315

14-
For more information about this error, try `rustc --explain E0277`.
16+
For more information about this error, try `rustc --explain E0525`.
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}`
2-
--> $DIR/closure-origin-array-diagnostics.rs:12:15
1+
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
2+
--> $DIR/closure-origin-array-diagnostics.rs:9:13
33
|
4+
LL | let c = || {
5+
| ^^ this closure implements `FnOnce`, not `Fn`
6+
LL | let [_, _s] = s;
7+
| - closure is `FnOnce` because it moves the variable `s` out of its environment
8+
LL | };
49
LL | expect_fn(c);
5-
| --------- ^ expected an `Fn()` closure, found `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}`
10+
| --------- - the requirement to implement `Fn` derives from here
611
| |
712
| required by a bound introduced by this call
813
|
9-
= help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}`
10-
= note: wrap the `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}` in a closure with no arguments: `|| { /* code */ }`
11-
= note: `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}` implements `FnOnce`, but it must implement `Fn`, which is more general
1214
note: required by a bound in `expect_fn`
1315
--> $DIR/closure-origin-array-diagnostics.rs:5:17
1416
|
@@ -17,4 +19,4 @@ LL | fn expect_fn<F: Fn()>(_f: F) {}
1719

1820
error: aborting due to previous error
1921

20-
For more information about this error, try `rustc --explain E0277`.
22+
For more information about this error, try `rustc --explain E0525`.
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}`
2-
--> $DIR/closure-origin-tuple-diagnostics.rs:12:15
1+
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
2+
--> $DIR/closure-origin-tuple-diagnostics.rs:9:13
33
|
4+
LL | let c = || {
5+
| ^^ this closure implements `FnOnce`, not `Fn`
6+
LL | let s = s.1;
7+
| --- closure is `FnOnce` because it moves the variable `s.1` out of its environment
8+
LL | };
49
LL | expect_fn(c);
5-
| --------- ^ expected an `Fn()` closure, found `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}`
10+
| --------- - the requirement to implement `Fn` derives from here
611
| |
712
| required by a bound introduced by this call
813
|
9-
= help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}`
10-
= note: wrap the `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}` in a closure with no arguments: `|| { /* code */ }`
11-
= note: `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}` implements `FnOnce`, but it must implement `Fn`, which is more general
1214
note: required by a bound in `expect_fn`
1315
--> $DIR/closure-origin-tuple-diagnostics.rs:5:17
1416
|
@@ -17,4 +19,4 @@ LL | fn expect_fn<F: Fn()>(_f: F) {}
1719

1820
error: aborting due to previous error
1921

20-
For more information about this error, try `rustc --explain E0277`.
22+
For more information about this error, try `rustc --explain E0525`.
+8-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
error[E0277]: expected a `Fn(u32)` closure, found `{closure@$DIR/closure-wrong-kind.rs:10:19: 10:22}`
2-
--> $DIR/closure-wrong-kind.rs:11:9
1+
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
2+
--> $DIR/closure-wrong-kind.rs:10:19
33
|
4+
LL | let closure = |_| foo(x);
5+
| ^^^ - closure is `FnOnce` because it moves the variable `x` out of its environment
6+
| |
7+
| this closure implements `FnOnce`, not `Fn`
48
LL | bar(closure);
5-
| --- ^^^^^^^ expected an `Fn(u32)` closure, found `{closure@$DIR/closure-wrong-kind.rs:10:19: 10:22}`
9+
| --- ------- the requirement to implement `Fn` derives from here
610
| |
711
| required by a bound introduced by this call
812
|
9-
= help: the trait `Fn<(u32,)>` is not implemented for closure `{closure@$DIR/closure-wrong-kind.rs:10:19: 10:22}`
10-
= note: `{closure@$DIR/closure-wrong-kind.rs:10:19: 10:22}` implements `FnOnce`, but it must implement `Fn`, which is more general
1113
note: required by a bound in `bar`
1214
--> $DIR/closure-wrong-kind.rs:6:11
1315
|
@@ -16,4 +18,4 @@ LL | fn bar<T: Fn(u32)>(_: T) {}
1618

1719
error: aborting due to previous error
1820

19-
For more information about this error, try `rustc --explain E0277`.
21+
For more information about this error, try `rustc --explain E0525`.

tests/ui/issues/issue-34349.stderr

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/issue-34349.rs:16:17: 16:19}`
2-
--> $DIR/issue-34349.rs:21:11
1+
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
2+
--> $DIR/issue-34349.rs:16:17
33
|
4+
LL | let diary = || {
5+
| ^^ this closure implements `FnMut`, not `Fn`
6+
LL | farewell.push_str("!!!");
7+
| -------- closure is `FnMut` because it mutates the variable `farewell` here
8+
...
49
LL | apply(diary);
5-
| ----- ^^^^^ expected an `Fn()` closure, found `{closure@$DIR/issue-34349.rs:16:17: 16:19}`
10+
| ----- ----- the requirement to implement `Fn` derives from here
611
| |
712
| required by a bound introduced by this call
813
|
9-
= help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/issue-34349.rs:16:17: 16:19}`
10-
= note: wrap the `{closure@$DIR/issue-34349.rs:16:17: 16:19}` in a closure with no arguments: `|| { /* code */ }`
11-
= note: `{closure@$DIR/issue-34349.rs:16:17: 16:19}` implements `FnMut`, but it must implement `Fn`, which is more general
1214
note: required by a bound in `apply`
1315
--> $DIR/issue-34349.rs:11:32
1416
|
@@ -17,4 +19,4 @@ LL | fn apply<F>(f: F) where F: Fn() {
1719

1820
error: aborting due to previous error
1921

20-
For more information about this error, try `rustc --explain E0277`.
22+
For more information about this error, try `rustc --explain E0525`.
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,57 @@
1-
error[E0277]: expected a `FnMut()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
2-
--> $DIR/move-ref-patterns-closure-captures.rs:17:19
3-
|
1+
error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
2+
--> $DIR/move-ref-patterns-closure-captures.rs:9:14
3+
|
4+
LL | let c1 = || {
5+
| ^^ this closure implements `FnOnce`, not `FnMut`
6+
...
7+
LL | drop::<U>(_x1);
8+
| --- closure is `FnOnce` because it moves the variable `_x1` out of its environment
9+
...
410
LL | accept_fn_mut(&c1);
5-
| ------------- ^^^ expected an `FnMut()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
11+
| ------------- --- the requirement to implement `FnMut` derives from here
612
| |
713
| required by a bound introduced by this call
814
|
9-
= help: the trait `FnMut<()>` is not implemented for closure `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
10-
= note: wrap the `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}` in a closure with no arguments: `|| { /* code */ }`
11-
= note: `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}` implements `FnOnce`, but it must implement `FnMut`, which is more general
1215
note: required by a bound in `accept_fn_mut`
1316
--> $DIR/move-ref-patterns-closure-captures.rs:4:31
1417
|
1518
LL | fn accept_fn_mut(_: &impl FnMut()) {}
1619
| ^^^^^^^ required by this bound in `accept_fn_mut`
1720

18-
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
19-
--> $DIR/move-ref-patterns-closure-captures.rs:18:15
20-
|
21+
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
22+
--> $DIR/move-ref-patterns-closure-captures.rs:9:14
23+
|
24+
LL | let c1 = || {
25+
| ^^ this closure implements `FnOnce`, not `Fn`
26+
...
27+
LL | drop::<U>(_x1);
28+
| --- closure is `FnOnce` because it moves the variable `_x1` out of its environment
29+
...
2130
LL | accept_fn(&c1);
22-
| --------- ^^^ expected an `Fn()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
31+
| --------- --- the requirement to implement `Fn` derives from here
2332
| |
2433
| required by a bound introduced by this call
2534
|
26-
= help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}`
27-
= note: wrap the `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}` in a closure with no arguments: `|| { /* code */ }`
28-
= note: `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}` implements `FnOnce`, but it must implement `Fn`, which is more general
2935
note: required by a bound in `accept_fn`
3036
--> $DIR/move-ref-patterns-closure-captures.rs:5:27
3137
|
3238
LL | fn accept_fn(_: &impl Fn()) {}
3339
| ^^^^ required by this bound in `accept_fn`
3440

35-
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:20:14: 20:16}`
36-
--> $DIR/move-ref-patterns-closure-captures.rs:26:15
37-
|
41+
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
42+
--> $DIR/move-ref-patterns-closure-captures.rs:20:14
43+
|
44+
LL | let c2 = || {
45+
| ^^ this closure implements `FnMut`, not `Fn`
46+
...
47+
LL | drop::<&mut U>(_x2);
48+
| --- closure is `FnMut` because it mutates the variable `_x2` here
49+
...
3850
LL | accept_fn(&c2);
39-
| --------- ^^^ expected an `Fn()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:20:14: 20:16}`
51+
| --------- --- the requirement to implement `Fn` derives from here
4052
| |
4153
| required by a bound introduced by this call
4254
|
43-
= help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/move-ref-patterns-closure-captures.rs:20:14: 20:16}`
44-
= note: wrap the `{closure@$DIR/move-ref-patterns-closure-captures.rs:20:14: 20:16}` in a closure with no arguments: `|| { /* code */ }`
45-
= note: `{closure@$DIR/move-ref-patterns-closure-captures.rs:20:14: 20:16}` implements `FnMut`, but it must implement `Fn`, which is more general
4655
note: required by a bound in `accept_fn`
4756
--> $DIR/move-ref-patterns-closure-captures.rs:5:27
4857
|
@@ -51,4 +60,4 @@ LL | fn accept_fn(_: &impl Fn()) {}
5160

5261
error: aborting due to 3 previous errors
5362

54-
For more information about this error, try `rustc --explain E0277`.
63+
For more information about this error, try `rustc --explain E0525`.
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13: 14:15}`
2-
--> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:15:9
1+
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
2+
--> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13
33
|
4+
LL | let c = || drop(y.0);
5+
| ^^ --- closure is `FnOnce` because it moves the variable `y` out of its environment
6+
| |
7+
| this closure implements `FnOnce`, not `Fn`
48
LL | foo(c);
5-
| --- ^ expected an `Fn()` closure, found `{closure@$DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13: 14:15}`
9+
| --- - the requirement to implement `Fn` derives from here
610
| |
711
| required by a bound introduced by this call
812
|
9-
= help: the trait `Fn<()>` is not implemented for closure `{closure@$DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13: 14:15}`
10-
= 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 */ }`
11-
= 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
1213
note: required by a bound in `foo`
1314
--> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:4:14
1415
|
@@ -19,4 +20,4 @@ LL | where F: Fn()
1920

2021
error: aborting due to previous error
2122

22-
For more information about this error, try `rustc --explain E0277`.
23+
For more information about this error, try `rustc --explain E0525`.

0 commit comments

Comments
 (0)