diff options
| author | Michael Goulet <michael@errs.io> | 2023-11-21 04:20:18 +0000 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2023-11-21 18:35:47 +0000 |
| commit | 128feaa2b40d063a834030d3ff9410c9327c5286 (patch) | |
| tree | 5068d61a731ce5dca2611a26baa7f1d4c3b90fdf | |
| parent | 93298ee0dd938c0fece0ee5dbafe851e54dd6386 (diff) | |
| download | rust-128feaa2b40d063a834030d3ff9410c9327c5286.tar.gz rust-128feaa2b40d063a834030d3ff9410c9327c5286.zip | |
Restore closure-kind error messages
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`. |
