From c29838843b0573a583f6457c176d9d49873e9eb5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 3 Jan 2025 02:45:09 +0000 Subject: [PATCH] Report impl has stricter requirements even when RPITIT inference gets in the way --- .../src/check/compare_impl_item.rs | 20 ++++++++++++++++ ...invalid-type-bound-suggest-issue-127555.rs | 2 +- ...lid-type-bound-suggest-issue-127555.stderr | 23 +++++++----------- ...-predicate-entailment-error.current.stderr | 22 ++++++++--------- ...lse-positive-predicate-entailment-error.rs | 4 ++-- .../in-trait/mismatched-where-clauses.rs | 12 ++++++++++ .../in-trait/mismatched-where-clauses.stderr | 12 ++++++++++ .../in-trait/return-dont-satisfy-bounds.rs | 2 +- .../return-dont-satisfy-bounds.stderr | 24 +++++++++---------- ...-hidden-types-self-implied-wf-via-param.rs | 2 +- ...den-types-self-implied-wf-via-param.stderr | 21 ++++++++-------- 11 files changed, 90 insertions(+), 54 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/mismatched-where-clauses.rs create mode 100644 tests/ui/impl-trait/in-trait/mismatched-where-clauses.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index a6b504de3dac1..4a957d5da242b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -529,6 +529,26 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); + // Check that the where clauses of the impl are satisfied by the hybrid param env. + // You might ask -- what does this have to do with RPITIT inference? Nothing. + // We check these because if the where clauses of the signatures do not match + // up, then we don't want to give spurious other errors that point at the RPITITs. + // They're not necessary to check, though, because we already check them in + // `compare_method_predicate_entailment`. + let impl_m_own_bounds = tcx.predicates_of(impl_m_def_id).instantiate_own_identity(); + for (predicate, span) in impl_m_own_bounds { + let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id); + let predicate = ocx.normalize(&normalize_cause, param_env, predicate); + + let cause = + ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem { + impl_item_def_id: impl_m_def_id, + trait_item_def_id: trait_m.def_id, + kind: impl_m.kind, + }); + ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); + } + // Normalize the impl signature with fresh variables for lifetime inference. let misc_cause = ObligationCause::misc(return_span, impl_m_def_id); let impl_sig = ocx.normalize( diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs index b4df58b3c25a8..4dfeab9e8c3f0 100644 --- a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs +++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs @@ -11,9 +11,9 @@ struct Baz {} impl Foo for Baz { async fn bar(&mut self, _func: F) -> () - //~^ ERROR `F` cannot be sent between threads safely where F: FnMut() + Send, + //~^ impl has stricter requirements than trait { () } diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr index e6379954776df..8d5cad4493e85 100644 --- a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr +++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr @@ -1,21 +1,14 @@ -error[E0277]: `F` cannot be sent between threads safely - --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:13:5 +error[E0276]: impl has stricter requirements than trait + --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:15:22 | -LL | / async fn bar(&mut self, _func: F) -> () -LL | | +LL | / fn bar(&mut self, func: F) -> impl std::future::Future + Send LL | | where -LL | | F: FnMut() + Send, - | |__________________________^ `F` cannot be sent between threads safely - | -note: required by a bound in `::bar` - --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:16:22 - | -LL | async fn bar(&mut self, _func: F) -> () - | --- required by a bound in this associated function +LL | | F: FnMut(); + | |___________________- definition of `bar` from trait ... -LL | F: FnMut() + Send, - | ^^^^ required by this bound in `::bar` +LL | F: FnMut() + Send, + | ^^^^ impl has extra requirement `F: Send` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0276`. diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr index e38e18857ef66..b6e7e02f3316c 100644 --- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr +++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr @@ -19,11 +19,11 @@ help: consider further restricting type parameter `F` with trait `MyFn` LL | F: Callback + MyFn, | +++++++++++ -error[E0277]: the trait bound `F: MyFn` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:36:30 +error[E0277]: the trait bound `F: Callback` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:42:12 | -LL | fn autobatch(self) -> impl Trait - | ^^^^^^^^^^ the trait `MyFn` is not implemented for `F` +LL | F: Callback, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn` is not implemented for `F` | note: required for `F` to implement `Callback` --> $DIR/false-positive-predicate-entailment-error.rs:14:21 @@ -32,14 +32,14 @@ LL | impl> Callback for F { | ------- ^^^^^^^^^^^ ^ | | | unsatisfied trait bound introduced here -note: required by a bound in `::autobatch` - --> $DIR/false-positive-predicate-entailment-error.rs:43:12 +note: the requirement `F: Callback` appears on the `impl`'s method `autobatch` but not on the corresponding trait's method + --> $DIR/false-positive-predicate-entailment-error.rs:25:8 | -LL | fn autobatch(self) -> impl Trait - | --------- required by a bound in this associated function +LL | trait ChannelSender { + | ------------- in this trait ... -LL | F: Callback, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `::autobatch` +LL | fn autobatch(self) -> impl Trait + | ^^^^^^^^^ this trait's method doesn't have the requirement `F: Callback` help: consider further restricting type parameter `F` with trait `MyFn` | LL | F: Callback + MyFn, @@ -118,7 +118,7 @@ LL | F: Callback + MyFn, | +++++++++++ error[E0277]: the trait bound `F: MyFn` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:43:12 + --> $DIR/false-positive-predicate-entailment-error.rs:42:12 | LL | F: Callback, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn` is not implemented for `F` diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs index 2987d183e0401..cbe6c32b8901c 100644 --- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs +++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs @@ -38,11 +38,11 @@ impl ChannelSender for Sender { //[current]~| ERROR the trait bound `F: MyFn` is not satisfied //[current]~| ERROR the trait bound `F: MyFn` is not satisfied //[current]~| ERROR the trait bound `F: MyFn` is not satisfied - //[current]~| ERROR the trait bound `F: MyFn` is not satisfied where F: Callback, //[current]~^ ERROR the trait bound `F: MyFn` is not satisfied - { + //[current]~| ERROR the trait bound `F: Callback` is not satisfied + { Thing } } diff --git a/tests/ui/impl-trait/in-trait/mismatched-where-clauses.rs b/tests/ui/impl-trait/in-trait/mismatched-where-clauses.rs new file mode 100644 index 0000000000000..a2c735cc126a3 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/mismatched-where-clauses.rs @@ -0,0 +1,12 @@ +trait Foo { + fn foo(s: S) -> impl Sized; +} + +trait Bar {} + +impl Foo for () { + fn foo(s: S) -> impl Sized where S: Bar {} + //~^ ERROR impl has stricter requirements than trait +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/mismatched-where-clauses.stderr b/tests/ui/impl-trait/in-trait/mismatched-where-clauses.stderr new file mode 100644 index 0000000000000..cc6e027cad775 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/mismatched-where-clauses.stderr @@ -0,0 +1,12 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/mismatched-where-clauses.rs:8:44 + | +LL | fn foo(s: S) -> impl Sized; + | ------------------------------ definition of `foo` from trait +... +LL | fn foo(s: S) -> impl Sized where S: Bar {} + | ^^^ impl has extra requirement `S: Bar` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0276`. diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs index ee47de2c73283..ff265e576b90f 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs @@ -8,7 +8,7 @@ impl Foo for Bar { fn foo>(self) -> impl Foo { //~^ ERROR: the trait bound `impl Foo: Foo` is not satisfied [E0277] //~| ERROR: the trait bound `Bar: Foo` is not satisfied [E0277] - //~| ERROR: the trait bound `F2: Foo` is not satisfied + //~| ERROR: impl has stricter requirements than trait self } } diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr index 663c9a7f2aeda..5cb80386b35f0 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr @@ -1,3 +1,12 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/return-dont-satisfy-bounds.rs:8:16 + | +LL | fn foo(self) -> impl Foo; + | -------------------------------- definition of `foo` from trait +... +LL | fn foo>(self) -> impl Foo { + | ^^^^^^^ impl has extra requirement `F2: Foo` + error[E0277]: the trait bound `impl Foo: Foo` is not satisfied --> $DIR/return-dont-satisfy-bounds.rs:8:34 | @@ -11,18 +20,6 @@ note: required by a bound in `Foo::{synthetic#0}` LL | fn foo(self) -> impl Foo; | ^^^^^^ required by this bound in `Foo::{synthetic#0}` -error[E0277]: the trait bound `F2: Foo` is not satisfied - --> $DIR/return-dont-satisfy-bounds.rs:8:34 - | -LL | fn foo>(self) -> impl Foo { - | ^^^^^^^^^^^^ the trait `Foo` is not implemented for `F2` - | -note: required by a bound in `>::foo` - --> $DIR/return-dont-satisfy-bounds.rs:8:16 - | -LL | fn foo>(self) -> impl Foo { - | ^^^^^^^ required by this bound in `>::foo` - error[E0277]: the trait bound `Bar: Foo` is not satisfied --> $DIR/return-dont-satisfy-bounds.rs:8:34 | @@ -38,4 +35,5 @@ LL | self error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0276, E0277. +For more information about an error, try `rustc --explain E0276`. diff --git a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs index 37b0b2297760a..7a3a59d37c6af 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs +++ b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs @@ -4,9 +4,9 @@ trait Extend { impl Extend for () { fn extend<'a: 'a>(s: &'a str) -> (Option<&'static &'a ()>, &'static str) - //~^ ERROR in type `&'static &'a ()`, reference has a longer lifetime than the data it references where 'a: 'static, + //~^ impl has stricter requirements than trait { (None, s) } diff --git a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr index 5ace64b690351..15bef5c78b05c 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr +++ b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr @@ -1,16 +1,17 @@ -error[E0491]: in type `&'static &'a ()`, reference has a longer lifetime than the data it references - --> $DIR/rpitit-hidden-types-self-implied-wf-via-param.rs:6:38 +error[E0276]: impl has stricter requirements than trait + --> $DIR/rpitit-hidden-types-self-implied-wf-via-param.rs:8:13 | -LL | fn extend<'a: 'a>(s: &'a str) -> (Option<&'static &'a ()>, &'static str) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn extend<'a: 'a>(_: &'a str) -> (impl Sized + 'a, &'static str); + | ----------------------------------------------------------------- definition of `extend` from trait +... +LL | 'a: 'static, + | ^^^^^^^ impl has extra requirement `'a: 'static` | - = note: the pointer is valid for the static lifetime -note: but the referenced data is only valid for the lifetime `'a` as defined here - --> $DIR/rpitit-hidden-types-self-implied-wf-via-param.rs:6:15 +help: copy the `where` clause predicates from the trait + | +LL | where 'a: 'a | -LL | fn extend<'a: 'a>(s: &'a str) -> (Option<&'static &'a ()>, &'static str) - | ^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0491`. +For more information about this error, try `rustc --explain E0276`.