1
Fork 0

Restore closure-kind error messages

This commit is contained in:
Michael Goulet 2023-11-21 04:20:18 +00:00
parent 93298ee0dd
commit 128feaa2b4
10 changed files with 136 additions and 70 deletions

View file

@ -906,12 +906,14 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot) 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 where
T: at::ToTrace<'tcx>, T: at::ToTrace<'tcx>,
{ {
let origin = &ObligationCause::dummy(); 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 pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool

View file

@ -98,6 +98,12 @@ pub trait TypeErrCtxtExt<'tcx> {
error: &SelectionError<'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 fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool;
fn report_const_param_not_wf( 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)) => { ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
let trait_predicate = bound_predicate.rebind(trait_predicate); let trait_predicate = bound_predicate.rebind(trait_predicate);
let trait_predicate = self.resolve_vars_if_possible(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) // FIXME(effects)
let predicate_is_const = false; let predicate_is_const = false;
@ -425,7 +436,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// reported on the binding definition (#56607). // reported on the binding definition (#56607).
return; return;
} }
let trait_ref = trait_predicate.to_poly_trait_ref();
let (post_message, pre_message, type_def, file_note) = self let (post_message, pre_message, type_def, file_note) = self
.get_parent_trait_ref(obligation.cause.code()) .get_parent_trait_ref(obligation.cause.code())
.map(|(t, s)| { .map(|(t, s)| {
@ -922,6 +932,38 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.emit(); 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 { fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool {
if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
obligation.cause.code() obligation.cause.code()

View file

@ -1,14 +1,16 @@
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21}` error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
--> $DIR/issue-26046-fn-mut.rs:8:5 --> $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) 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)>` = 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 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`.

View file

@ -1,14 +1,16 @@
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26}` error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> $DIR/issue-26046-fn-once.rs:8:5 --> $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) 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)>` = 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 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`.

View file

@ -1,14 +1,16 @@
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/closure-origin-array-diagnostics.rs:9:13: 9:15}` error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> $DIR/closure-origin-array-diagnostics.rs:12:15 --> $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); 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 | 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` note: required by a bound in `expect_fn`
--> $DIR/closure-origin-array-diagnostics.rs:5:17 --> $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 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`.

View file

@ -1,14 +1,16 @@
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/closure-origin-tuple-diagnostics.rs:9:13: 9:15}` error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> $DIR/closure-origin-tuple-diagnostics.rs:12:15 --> $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); 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 | 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` note: required by a bound in `expect_fn`
--> $DIR/closure-origin-tuple-diagnostics.rs:5:17 --> $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 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`.

View file

@ -1,13 +1,15 @@
error[E0277]: expected a `Fn(u32)` closure, found `{closure@$DIR/closure-wrong-kind.rs:10:19: 10:22}` error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> $DIR/closure-wrong-kind.rs:11:9 --> $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); 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 | 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` note: required by a bound in `bar`
--> $DIR/closure-wrong-kind.rs:6:11 --> $DIR/closure-wrong-kind.rs:6:11
| |
@ -16,4 +18,4 @@ LL | fn bar<T: Fn(u32)>(_: T) {}
error: aborting due to previous error 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`.

View file

@ -1,14 +1,16 @@
error[E0277]: expected a `Fn()` closure, found `{closure@$DIR/issue-34349.rs:16:17: 16:19}` error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
--> $DIR/issue-34349.rs:21:11 --> $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); 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 | 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` note: required by a bound in `apply`
--> $DIR/issue-34349.rs:11:32 --> $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 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`.

View file

@ -1,48 +1,57 @@
error[E0277]: expected a `FnMut()` closure, found `{closure@$DIR/move-ref-patterns-closure-captures.rs:9:14: 9:16}` error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
--> $DIR/move-ref-patterns-closure-captures.rs:17:19 --> $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); 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 | 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` note: required by a bound in `accept_fn_mut`
--> $DIR/move-ref-patterns-closure-captures.rs:4:31 --> $DIR/move-ref-patterns-closure-captures.rs:4:31
| |
LL | fn accept_fn_mut(_: &impl FnMut()) {} LL | fn accept_fn_mut(_: &impl FnMut()) {}
| ^^^^^^^ required by this bound in `accept_fn_mut` | ^^^^^^^ 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}` error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> $DIR/move-ref-patterns-closure-captures.rs:18:15 --> $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); 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 | 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` note: required by a bound in `accept_fn`
--> $DIR/move-ref-patterns-closure-captures.rs:5:27 --> $DIR/move-ref-patterns-closure-captures.rs:5:27
| |
LL | fn accept_fn(_: &impl Fn()) {} LL | fn accept_fn(_: &impl Fn()) {}
| ^^^^ required by this bound in `accept_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}` error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
--> $DIR/move-ref-patterns-closure-captures.rs:26:15 --> $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); 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 | 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` note: required by a bound in `accept_fn`
--> $DIR/move-ref-patterns-closure-captures.rs:5:27 --> $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 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`.

View file

@ -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}` 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:15:9 --> $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); 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 | 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` note: required by a bound in `foo`
--> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:4:14 --> $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 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`.