Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show pending obligations as unsatisfied constraints in report_similar_impl_candidates #134348

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

soareschen
Copy link

Fixes: #134346

Summary

This PR attempts to fix the issue in #134346, by additional help hints for each unsatisfied indirect constraint inside a blanket implementation.

Details

To provide the extra information, a new variant Select(PredicateObligations<'tcx>) is added to ScrubbedTraitError<'tcx> to extract the pending_obligations returned from select_where_possible. Then inside report_similar_impl_candidates, we iterate through every pending obligation in the errors, and print them out as a help hint.

Potential Issues

This is my first contribution to the Rust compiler project. I'm not sure of the best way to present the error messages, or handle them anywhere else in the codebase. If there are better ways to implement the improvement, I'm happy to modify the PR according to the suggestions.

An unresolved issue here is that the fix is only implemented for the old Rust trait solver. Compared to OldSolverError, I don't see the pending_obligations field to be present inside NextSolverError. So I'm unsure of the best way to keep this forward compatible with the upcoming trait solver.

I'm also not sure if the fix here would produce too noisy errors outside of my specific use case. When I test this fix with more complex projects that I have, the error messages may contain many unresolved constraints. However when scanning through all items, I determined that none of the listed unresolved constraints should be considered uninformative noise. Hence, I do think that it is essential to have all unresolved constraints listed in the error message.

@rustbot
Copy link
Collaborator

rustbot commented Dec 15, 2024

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @wesleywiser (or someone else) some time within the next two weeks.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 15, 2024
@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-llvm-18 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
#16 exporting to docker image format
#16 sending tarball 27.1s done
#16 DONE 39.9s
##[endgroup]
Setting extra environment values for docker:  --env ENABLE_GCC_CODEGEN=1 --env GCC_EXEC_PREFIX=/usr/lib/gcc/
[CI_JOB_NAME=x86_64-gnu-llvm-18]
debug: `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` configured.
---
sccache: Starting the server...
##[group]Configure the build
configure: processing command line
configure: 
configure: build.configure-args := ['--build=x86_64-unknown-linux-gnu', '--llvm-root=/usr/lib/llvm-18', '--enable-llvm-link-shared', '--set', 'rust.randomize-layout=true', '--set', 'rust.thin-lto-import-instr-limit=10', '--enable-verbose-configure', '--enable-sccache', '--disable-manage-submodules', '--enable-locked-deps', '--enable-cargo-native-static', '--set', 'rust.codegen-units-std=1', '--set', 'dist.compression-profile=balanced', '--dist-compression-formats=xz', '--set', 'rust.lld=false', '--disable-dist-src', '--release-channel=nightly', '--enable-debug-assertions', '--enable-overflow-checks', '--enable-llvm-assertions', '--set', 'rust.verify-llvm-ir', '--set', 'rust.codegen-backends=llvm,cranelift,gcc', '--set', 'llvm.static-libstdcpp', '--enable-new-symbol-mangling']
configure: target.x86_64-unknown-linux-gnu.llvm-config := /usr/lib/llvm-18/bin/llvm-config
configure: llvm.link-shared     := True
configure: rust.randomize-layout := True
configure: rust.thin-lto-import-instr-limit := 10
---
To only update this specific test, also pass `--test-args errors/trait-bound-error-spans/blame-trait-error.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--check-cfg" "cfg(FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/errors/trait-bound-error-spans/blame-trait-error" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers"
--- stderr -------------------------------
--- stderr -------------------------------
error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(Wrapper { value: Burrito { filling: q } });
   |     ----                                     ^ the trait `T3` is not implemented for `Q`
   |     required by a bound introduced by this call
   |
   |
note: required for `Burrito<Q>` to implement `T2`
   |
   |
LL | impl<A: T3> T2 for Burrito<A> {}
   |         |
   |         unsatisfied trait bound introduced here
   |         unsatisfied trait bound introduced here
note: required for `Wrapper<Burrito<Q>>` to implement `T1`
   |
   |
LL | impl<B: T2> T1 for Wrapper<B> {}
   |         |
   |         unsatisfied trait bound introduced here
note: required by a bound in `want`
  --> /checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs:25:12
  --> /checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs:25:12
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {

error[E0277]: `()` is not an iterator
##[error]  --> /checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs:56:15
   |
---
   = help: the trait `T1` is implemented for `Option<It>`
note: required for `Option<()>` to implement `T1`
  --> /checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs:21:20
   |
LL | impl<It: Iterator> T1 for Option<It> {}
   |          |
   |          unsatisfied trait bound introduced here
note: required by a bound in `want`
  --> /checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs:25:12
  --> /checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs:25:12
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
error[E0277]: `Q` is not an iterator
##[error]  --> /checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs:59:15
   |
   |
LL |     want(Some(q));
   |     ----      ^ `Q` is not an iterator
   |     required by a bound introduced by this call
   |
   |
note: required for `Option<Q>` to implement `T1`
   |
   |
LL | impl<It: Iterator> T1 for Option<It> {}
   |          |
   |          unsatisfied trait bound introduced here
note: required by a bound in `want`
  --> /checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs:25:12
  --> /checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs:25:12
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `Iterator`
   |
LL | fn example<Q: std::iter::Iterator>(q: Q) {

error[E0277]: `Q` is not an iterator
##[error]  --> /checkout/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs:62:16
   |
   |
LL |     want(&Some(q));
   |     ----       ^ `Q` is not an iterator
   |     required by a bound introduced by this call
   |
   |
note: required for `Option<Q>` to implement `T1`
   |
   |
LL | impl<It: Iterator> T1 for Option<It> {}
   |          |
   |          unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: 1 redundant requirement hidden
   = note: required for `&Option<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `Iterator`
   |
LL | fn example<Q: std::iter::Iterator>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleTuple::ExampleTupleVariant(q));
   |     ----                                    ^ the trait `T3` is not implemented for `Q`
   |     required by a bound introduced by this call
   |
   |
note: required for `ExampleTuple<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleTuple<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleTuple<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleTupleVariant(q));
   |     ----                      ^ the trait `T3` is not implemented for `Q`
   |     required by a bound introduced by this call
   |
   |
note: required for `ExampleTuple<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleTuple<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleTuple<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleOtherTuple::ExampleTupleVariant(q));
   |     ----                                         ^ the trait `T3` is not implemented for `Q`
   |     required by a bound introduced by this call
   |
   |
note: required for `ExampleTuple<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleTuple<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleTuple<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleDifferentTupleVariantName(q));
   |     ----                                   ^ the trait `T3` is not implemented for `Q`
   |     required by a bound introduced by this call
   |
   |
note: required for `ExampleTuple<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleTuple<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleTuple<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleYetAnotherTupleVariantName(q));
   |     ----                                    ^ the trait `T3` is not implemented for `Q`
   |     required by a bound introduced by this call
   |
   |
note: required for `ExampleTuple<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleTuple<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleTuple<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleStruct::ExampleStructVariant { field: q });
   |     ---- required by a bound introduced by this call   ^ the trait `T3` is not implemented for `Q`
   |
note: required for `ExampleStruct<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleStruct<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleStruct<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleStructVariant { field: q });
   |     ----                                ^ the trait `T3` is not implemented for `Q`
   |     required by a bound introduced by this call
   |
   |
note: required for `ExampleStruct<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleStruct<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleStruct<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleOtherStruct::ExampleStructVariant { field: q });
   |     ---- required by a bound introduced by this call        ^ the trait `T3` is not implemented for `Q`
   |
note: required for `ExampleStruct<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleStruct<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleStruct<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleDifferentStructVariantName { field: q });
   |     ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`
   |
note: required for `ExampleStruct<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleStruct<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleStruct<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleYetAnotherStructVariantName { field: q });
   |     ---- required by a bound introduced by this call  ^ the trait `T3` is not implemented for `Q`
   |
note: required for `ExampleStruct<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleStruct<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleStruct<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleActuallyTupleStruct(q, 0));
   |     ----                             ^ the trait `T3` is not implemented for `Q`
   |     required by a bound introduced by this call
   |
   |
note: required for `ExampleActuallyTupleStruct<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleActuallyTupleStruct<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleActuallyTupleStruct<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {


error[E0277]: the trait bound `Q: T3` is not satisfied
   |
   |
LL |     want(&ExampleActuallyTupleStructOther(q, 0));
   |     ----                                  ^ the trait `T3` is not implemented for `Q`
   |     required by a bound introduced by this call
   |
   |
note: required for `ExampleActuallyTupleStruct<Q>` to implement `T1`
   |
   |
LL | impl<A> T1 for ExampleActuallyTupleStruct<A> where A: T3 {}
   |         ^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^          -- unsatisfied trait bound introduced here
   = note: 1 redundant requirement hidden
   = note: required for `&ExampleActuallyTupleStruct<Q>` to implement `T1`
note: required by a bound in `want`
   |
   |
LL | fn want<V: T1>(_x: V) {}
   |            ^^ required by this bound in `want`
help: consider restricting type parameter `Q` with trait `T3`
   |
LL | fn example<Q: T3>(q: Q) {

error: aborting due to 16 previous errors

For more information about this error, try `rustc --explain E0277`.
---

50    |                                              |
51    |                                              the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
52    |
+    = help: the following constraint is not satisfied: `impl Debug: From<impl Into<u32>>`
53    = help: the trait `Into<U>` is implemented for `T`
54    = note: required for `impl Into<u32>` to implement `Into<impl Debug>`

61    |                                  |
62    |                                  the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
63    |
63    |
+    = help: the following constraint is not satisfied: `impl Debug: From<impl Into<u32>>`
64    = help: the trait `Into<U>` is implemented for `T`
65    = note: required for `impl Into<u32>` to implement `Into<impl Debug>`


The actual stderr differed from the expected stderr.
To update references, rerun the tests and pass the `--bless` flag
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args impl-trait/nested_impl_trait.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/impl-trait/nested_impl_trait.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--check-cfg" "cfg(FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/impl-trait/nested_impl_trait" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers"
--- stderr -------------------------------
error[E0666]: nested `impl Trait` is not allowed
##[error]  --> /checkout/tests/ui/impl-trait/nested_impl_trait.rs:6:56
   |
   |
LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
   |                                              |         |
   |                                              |         nested `impl Trait` here
   |                                              outer `impl Trait`


error[E0666]: nested `impl Trait` is not allowed
##[error]  --> /checkout/tests/ui/impl-trait/nested_impl_trait.rs:10:42
   |
LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
   |                                |         |
   |                                |         nested `impl Trait` here
   |                                outer `impl Trait`


error[E0666]: nested `impl Trait` is not allowed
##[error]  --> /checkout/tests/ui/impl-trait/nested_impl_trait.rs:14:37
   |
LL | fn bad_in_arg_position(_: impl Into<impl Debug>) { }
   |                           |         |
   |                           |         nested `impl Trait` here
   |                           outer `impl Trait`


error[E0666]: nested `impl Trait` is not allowed
##[error]  --> /checkout/tests/ui/impl-trait/nested_impl_trait.rs:19:44
   |
LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
   |                                  |         |
   |                                  |         nested `impl Trait` here
   |                                  outer `impl Trait`


error[E0562]: `impl Trait` is not allowed in `fn` pointer return types
##[error]  --> /checkout/tests/ui/impl-trait/nested_impl_trait.rs:10:32
   |
LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
   |
   = note: `impl Trait` is only allowed in arguments and return types of functions and methods


error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
   |
   |
LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
   |                                              ^^^^^^^^^^^^^^^^^^^^^   - return type was inferred to be `impl Into<u32>` here
   |                                              the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
   |
   = help: the following constraint is not satisfied: `impl Debug: From<impl Into<u32>>`
   = help: the trait `Into<U>` is implemented for `T`
   = help: the trait `Into<U>` is implemented for `T`
   = note: required for `impl Into<u32>` to implement `Into<impl Debug>`

error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
   |
   |
LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
   |                                  ^^^^^^^^^^^^^^^^^^^^^   - return type was inferred to be `impl Into<u32>` here
   |                                  the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
   |
   = help: the following constraint is not satisfied: `impl Debug: From<impl Into<u32>>`
   = help: the trait `Into<U>` is implemented for `T`
   = help: the trait `Into<U>` is implemented for `T`
   = note: required for `impl Into<u32>` to implement `Into<impl Debug>`
error: aborting due to 7 previous errors

Some errors have detailed explanations: E0277, E0562, E0666.
For more information about an error, try `rustc --explain E0277`.
---
diff of stderr:

8    |     --- return type was inferred to be `Bar` here
9    |
10    = help: the trait `PartialEq<(Foo, i32)>` is not implemented for `Bar`
+    = help: the following constraint is not satisfied: `Bar: PartialEq<(Foo, i32)>`
+    = help: the following constraint is not satisfied: `Bar: PartialEq<(Foo, i32)>`
11    = help: the trait `PartialEq<(Bar, i32)>` is implemented for `Bar`
13 error: aborting due to 1 previous error


The actual stderr differed from the expected stderr.
The actual stderr differed from the expected stderr.
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args impl-trait/recursive-type-alias-impl-trait-declaration.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--check-cfg" "cfg(FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers"
--- stderr -------------------------------
--- stderr -------------------------------
error[E0277]: can't compare `Bar` with `(Foo, i32)`
   |
LL | fn foo() -> Foo {
LL | fn foo() -> Foo {
   |             ^^^ no implementation for `Bar == (Foo, i32)`
LL |     //~^ ERROR can't compare `Bar` with `(Foo, i32)`
   |     --- return type was inferred to be `Bar` here
   |
   |
   = help: the trait `PartialEq<(Foo, i32)>` is not implemented for `Bar`
   = help: the following constraint is not satisfied: `Bar: PartialEq<(Foo, i32)>`
   = help: the following constraint is not satisfied: `Bar: PartialEq<(Foo, i32)>`
   = help: the trait `PartialEq<(Bar, i32)>` is implemented for `Bar`
error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
------------------------------------------
------------------------------------------


---- [ui] tests/ui/kindck/kindck-impl-type-params.rs stdout ----
Saved the actual stderr to "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/kindck/kindck-impl-type-params/kindck-impl-type-params.stderr"
diff of stderr:

80 LL |     let a = t as Box<dyn Gettable<String>>;
82    |
+    = help: the following constraint is not satisfied: `String: Copy`
+    = help: the following constraint is not satisfied: `String: Copy`
83    = help: the trait `Gettable<T>` is implemented for `S<T>`
84 note: required for `S<String>` to implement `Gettable<String>`


96 LL |     let a: Box<dyn Gettable<Foo>> = t;
98    |
+    = help: the following constraint is not satisfied: `Foo: Copy`
+    = help: the following constraint is not satisfied: `Foo: Copy`
99    = help: the trait `Gettable<T>` is implemented for `S<T>`
100 note: required for `S<Foo>` to implement `Gettable<Foo>`


The actual stderr differed from the expected stderr.
To update references, rerun the tests and pass the `--bless` flag
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args kindck/kindck-impl-type-params.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/kindck/kindck-impl-type-params.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--check-cfg" "cfg(FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/kindck/kindck-impl-type-params" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers"
--- stderr -------------------------------
error[E0277]: `T` cannot be sent between threads safely
##[error]  --> /checkout/tests/ui/kindck/kindck-impl-type-params.rs:16:13
   |
   |
LL |     let a = &t as &dyn Gettable<T>;
   |             ^^ `T` cannot be sent between threads safely
   |
note: required for `S<T>` to implement `Gettable<T>`
   |
   |
LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
   |         |
   |         unsatisfied trait bound introduced here
   |         unsatisfied trait bound introduced here
   = note: required for the cast from `&S<T>` to `&dyn Gettable<T>`
help: consider restricting type parameter `T` with trait `Send`
   |
LL | fn f<T: std::marker::Send>(val: T) {

error[E0277]: the trait bound `T: Copy` is not satisfied
##[error]  --> /checkout/tests/ui/kindck/kindck-impl-type-params.rs:16:13
   |
   |
LL |     let a = &t as &dyn Gettable<T>;
   |             ^^ the trait `Copy` is not implemented for `T`
   |
note: required for `S<T>` to implement `Gettable<T>`
   |
   |
LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
   |                |
   |                unsatisfied trait bound introduced here
   |                unsatisfied trait bound introduced here
   = note: required for the cast from `&S<T>` to `&dyn Gettable<T>`
help: consider restricting type parameter `T` with trait `Copy`
   |
LL | fn f<T: std::marker::Copy>(val: T) {

error[E0277]: `T` cannot be sent between threads safely
##[error]  --> /checkout/tests/ui/kindck/kindck-impl-type-params.rs:23:31
   |
   |
LL |     let a: &dyn Gettable<T> = &t;
   |                               ^^ `T` cannot be sent between threads safely
   |
note: required for `S<T>` to implement `Gettable<T>`
   |
   |
LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
   |         |
   |         unsatisfied trait bound introduced here
   |         unsatisfied trait bound introduced here
   = note: required for the cast from `&S<T>` to `&dyn Gettable<T>`
help: consider restricting type parameter `T` with trait `Send`
   |
LL | fn g<T: std::marker::Send>(val: T) {

error[E0277]: the trait bound `T: Copy` is not satisfied
##[error]  --> /checkout/tests/ui/kindck/kindck-impl-type-params.rs:23:31
   |
   |
LL |     let a: &dyn Gettable<T> = &t;
   |                               ^^ the trait `Copy` is not implemented for `T`
   |
note: required for `S<T>` to implement `Gettable<T>`
   |
   |
LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
   |                |
   |                unsatisfied trait bound introduced here
   |                unsatisfied trait bound introduced here
   = note: required for the cast from `&S<T>` to `&dyn Gettable<T>`
help: consider restricting type parameter `T` with trait `Copy`
   |
LL | fn g<T: std::marker::Copy>(val: T) {

error[E0277]: the trait bound `String: Copy` is not satisfied
##[error]  --> /checkout/tests/ui/kindck/kindck-impl-type-params.rs:36:13
   |
   |
LL |     let a = t as Box<dyn Gettable<String>>;
   |
   = help: the following constraint is not satisfied: `String: Copy`
   = help: the following constraint is not satisfied: `String: Copy`
   = help: the trait `Gettable<T>` is implemented for `S<T>`
note: required for `S<String>` to implement `Gettable<String>`
   |
   |
LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
   |                |
   |                unsatisfied trait bound introduced here
   |                unsatisfied trait bound introduced here
   = note: required for the cast from `Box<S<String>>` to `Box<dyn Gettable<String>>`
error[E0277]: the trait bound `Foo: Copy` is not satisfied
##[error]  --> /checkout/tests/ui/kindck/kindck-impl-type-params.rs:44:37
   |
   |
LL |     let a: Box<dyn Gettable<Foo>> = t;
   |
   = help: the following constraint is not satisfied: `Foo: Copy`
   = help: the following constraint is not satisfied: `Foo: Copy`
   = help: the trait `Gettable<T>` is implemented for `S<T>`
note: required for `S<Foo>` to implement `Gettable<Foo>`
   |
   |
LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
   |                |
   |                unsatisfied trait bound introduced here
   |                unsatisfied trait bound introduced here
   = note: required for the cast from `Box<S<Foo>>` to `Box<dyn Gettable<Foo>>`
help: consider annotating `Foo` with `#[derive(Copy)]`
LL +     #[derive(Copy)]
LL |     struct Foo; // does not impl Copy
   |


error: lifetime may not live long enough
##[error]  --> /checkout/tests/ui/kindck/kindck-impl-type-params.rs:30:19
   |
LL | fn foo<'a>() {
   |        -- lifetime `'a` defined here
LL |     let t: S<&'a isize> = S(marker::PhantomData);
LL |     let a = &t as &dyn Gettable<&'a isize>;
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0277`.
------------------------------------------
------------------------------------------


---- [ui] tests/ui/type-alias-impl-trait/self-referential-4.rs stdout ----
Saved the actual stderr to "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/type-alias-impl-trait/self-referential-4/self-referential-4.stderr"

7    |     - return type was inferred to be `&i32` here
8    |
8    |
9    = help: the trait `PartialEq<Bar<'b, 'static>>` is not implemented for `&i32`
+    = help: the following constraint is not satisfied: `i32: PartialEq<Bar<'static, 'static>>`
+    = help: the following constraint is not satisfied: `i32: PartialEq<Bar<'static, 'static>>`
11 
11 
12 error[E0277]: can't compare `&i32` with `Foo<'static, 'b>`
18    |     - return type was inferred to be `&i32` here
19    |
19    |
20    = help: the trait `PartialEq<Foo<'static, 'b>>` is not implemented for `&i32`
+    = help: the following constraint is not satisfied: `i32: PartialEq<Foo<'static, 'b>>`
+    = help: the following constraint is not satisfied: `i32: PartialEq<Foo<'static, 'b>>`
22 
22 
23 error[E0277]: can't compare `&i32` with `Moo<'static, 'a>`
29    |     - return type was inferred to be `&i32` here
30    |
30    |
31    = help: the trait `PartialEq<Moo<'static, 'a>>` is not implemented for `&i32`
+    = help: the following constraint is not satisfied: `i32: PartialEq<Moo<'static, 'static>>`
+    = help: the following constraint is not satisfied: `i32: PartialEq<Moo<'static, 'static>>`
33 
34 error: aborting due to 3 previous errors



The actual stderr differed from the expected stderr.
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args type-alias-impl-trait/self-referential-4.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/type-alias-impl-trait/self-referential-4.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--check-cfg" "cfg(FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/type-alias-impl-trait/self-referential-4" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers"
--- stderr -------------------------------
--- stderr -------------------------------
error[E0277]: can't compare `&i32` with `Bar<'b, 'static>`
   |
   |
LL | fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
   |                               ^^^^^^^^^^^ no implementation for `&i32 == Bar<'b, 'static>`
LL |     i //~^ ERROR can't compare `&i32` with `Bar<'b, 'static>`
   |     - return type was inferred to be `&i32` here
   |
   = help: the trait `PartialEq<Bar<'b, 'static>>` is not implemented for `&i32`
   = help: the following constraint is not satisfied: `i32: PartialEq<Bar<'static, 'static>>`
   = help: the following constraint is not satisfied: `i32: PartialEq<Bar<'static, 'static>>`


error[E0277]: can't compare `&i32` with `Foo<'static, 'b>`
   |
   |
LL | fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> {
   |                               ^^^^^^^^^^^ no implementation for `&i32 == Foo<'static, 'b>`
LL |     i //~^ ERROR can't compare `&i32` with `Foo<'static, 'b>`
   |     - return type was inferred to be `&i32` here
   |
   = help: the trait `PartialEq<Foo<'static, 'b>>` is not implemented for `&i32`
   = help: the following constraint is not satisfied: `i32: PartialEq<Foo<'static, 'b>>`
   = help: the following constraint is not satisfied: `i32: PartialEq<Foo<'static, 'b>>`


error[E0277]: can't compare `&i32` with `Moo<'static, 'a>`
   |
   |
LL | fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> {
   |                               ^^^^^^^^^^^ no implementation for `&i32 == Moo<'static, 'a>`
LL |     i //~^ ERROR can't compare `&i32` with `Moo<'static, 'a>`
   |     - return type was inferred to be `&i32` here
   |
   = help: the trait `PartialEq<Moo<'static, 'a>>` is not implemented for `&i32`
   = help: the following constraint is not satisfied: `i32: PartialEq<Moo<'static, 'static>>`
   = help: the following constraint is not satisfied: `i32: PartialEq<Moo<'static, 'static>>`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.
---
diff of stderr:

8    |     - return type was inferred to be `&i32` here
9    |
10    = help: the trait `PartialEq<Bar<'b, 'a>>` is not implemented for `&i32`
+    = help: the following constraint is not satisfied: `i32: PartialEq<Bar<'a, 'b>>`
+    = help: the following constraint is not satisfied: `i32: PartialEq<Bar<'a, 'b>>`
12 
12 
13 error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)`

The actual stderr differed from the expected stderr.
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args type-alias-impl-trait/self-referential.rs`
To only update this specific test, also pass `--test-args type-alias-impl-trait/self-referential.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/type-alias-impl-trait/self-referential.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--check-cfg" "cfg(FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/type-alias-impl-trait/self-referential" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers"
--- stderr -------------------------------
--- stderr -------------------------------
error[E0277]: can't compare `&i32` with `Bar<'b, 'a>`
   |
   |
LL | fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
   |                               ^^^^^^^^^^^ no implementation for `&i32 == Bar<'b, 'a>`
LL |     //~^ ERROR can't compare `&i32` with `Bar<'b, 'a>`
   |     - return type was inferred to be `&i32` here
   |
   |
   = help: the trait `PartialEq<Bar<'b, 'a>>` is not implemented for `&i32`
   = help: the following constraint is not satisfied: `i32: PartialEq<Bar<'a, 'b>>`
   = help: the following constraint is not satisfied: `i32: PartialEq<Bar<'a, 'b>>`


error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)`
   |
   |
LL | fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> {
   |                               ^^^^^^^^^^^ no implementation for `&i32 == (i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)`
LL |     //~^ ERROR can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)`
LL |     (42, i)
   |     ------- return type was inferred to be `(i32, &i32)` here
   |
   = help: the trait `PartialEq<(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)>` is not implemented for `&i32`


error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)`
   |
   |
LL | fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> {
   |                               ^^^^^^^^^^^ no implementation for `&i32 == (i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)`
LL |     //~^ ERROR can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)`
LL |     (42, i)
   |     ------- return type was inferred to be `(i32, &i32)` here
   |
   = help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)>` is not implemented for `&i32`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.

@soareschen
Copy link
Author

From the CI failure, it looks like the patch introduces a lot of redundant hints with constraints that are basically equivalent to the original constraint.

I can try to work on hiding pending obligations that match the original. But I'm not quite sure how to do that within report_similar_impl_candidates. Given the pending PredicateObligation<'tcx>, I'm not quite sure what other values I should use, and whether I can perform the comparison with a different type.

Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not totally certain what the motivation here is because there's no test and the issue you linked has a pretty large minimization, so I'm not actually sure what the root cause is and whether this is actually the best way to show that information.

Can you try to turn this into a more minimal example to try to explain better what information the compiler is missing in its diagnostics outputs?

Otherwise I'm not totally certain we can give good feedback on the approach in this PR, especially because making a totally new way of reporting unsatisfied predicates on a pretty common codepath (for unsatisfied impls) seems a bit excessive on first glance.

@@ -17,6 +17,8 @@ use crate::traits::Obligation;
pub enum ScrubbedTraitError<'tcx> {
/// A real error. This goal definitely does not hold.
TrueError,
// A select error with pending obligations
Select(PredicateObligations<'tcx>),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that it's not really documented, but this is antithetical to the design of ScrubbedTraitError. That type should be very lightweight.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
5 participants