Repository: rust-lang/rust
Pull request: Avoid ICE in explicit reference cast suggestion for unrelated leaf pr…

<!-- homu-ignore:start -->
<!--
If this PR is related to an unstable feature or an otherwise tracked effort,
please link to the relevant tracking issue here. If you don't know of a related
tracking issue or there are none, feel free to ignore this.

This PR will get automatically assigned to a reviewer. In case you would like
a specific user to review your work, you can assign it to them by using

    r? <reviewer name>
-->
<!-- homu-ignore:end -->

Fixes rust-lang/rust#154403

The explicit reference cast suggestion in was enabled based on `main_trait_predicate` being `From`/`TryFrom`, but it then extracted the source type from `leaf_trait_predicate`.

That is only valid when the leaf obligation is also part of the `From`/`TryFrom` conversion family.

Changed files:
filename: compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
patch: @@ -285,14 +285,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
 
                         let trait_def_id = main_trait_predicate.def_id();
-                        if self.tcx.is_diagnostic_item(sym::From, trait_def_id)
-                            || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id)
+                        let leaf_trait_def_id = leaf_trait_predicate.def_id();
+                        if (self.tcx.is_diagnostic_item(sym::From, trait_def_id)
+                            || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id))
+                            && (self.tcx.is_diagnostic_item(sym::From, leaf_trait_def_id)
+                                || self.tcx.is_diagnostic_item(sym::TryFrom, leaf_trait_def_id))
                         {
                             let trait_ref = leaf_trait_predicate.skip_binder().trait_ref;
 
-                            // Defensive: next-solver may produce fewer args than expected.
-                            if trait_ref.args.len() > 1 {
-                                let found_ty = trait_ref.args.type_at(1);
+                            if let Some(found_ty) = trait_ref.args.get(1).and_then(|arg| arg.as_type())
+                            {
                                 let ty = main_trait_predicate.skip_binder().self_ty();
 
                                 if let Some(cast_ty) = self.find_explicit_cast_type(

filename: tests/ui/traits/explicit-reference-cast-unrelated-leaf.rs
patch: @@ -0,0 +1,21 @@
+trait Output<'a> {
+    type Type;
+}
+
+struct Wrapper;
+
+impl Wrapper {
+    fn do_something_wrapper<O, F>(self, _: F)
+    where
+        for<'a> F: Output<'a>,
+        for<'a> O: From<<F as Output<'a>>::Type>,
+    {
+    }
+}
+
+fn main() {
+    let wrapper = Wrapper;
+    wrapper.do_something_wrapper(|value| ());
+    //~^ ERROR the trait bound `for<'a> {closure@
+    //~| ERROR the trait bound `for<'a> _: From<<{closure@
+}

filename: tests/ui/traits/explicit-reference-cast-unrelated-leaf.stderr
patch: @@ -0,0 +1,47 @@
+error[E0277]: the trait bound `for<'a> {closure@$DIR/explicit-reference-cast-unrelated-leaf.rs:18:34: 18:41}: Output<'a>` is not satisfied
+  --> $DIR/explicit-reference-cast-unrelated-leaf.rs:18:34
+   |
+LL |     wrapper.do_something_wrapper(|value| ());
+   |             -------------------- ^^^^^^^^^^ unsatisfied trait bound
+   |             |
+   |             required by a bound introduced by this call
+   |
+   = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/explicit-reference-cast-unrelated-leaf.rs:18:34: 18:41}`
+help: this trait has no implementations, consider adding one
+  --> $DIR/explicit-reference-cast-unrelated-leaf.rs:1:1
+   |
+LL | trait Output<'a> {
+   | ^^^^^^^^^^^^^^^^
+note: required by a bound in `Wrapper::do_something_wrapper`
+  --> $DIR/explicit-reference-cast-unrelated-leaf.rs:10:20
+   |
+LL |     fn do_something_wrapper<O, F>(self, _: F)
+   |        -------------------- required by a bound in this associated function
+LL |     where
+LL |         for<'a> F: Output<'a>,
+   |                    ^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper`
+
+error[E0277]: the trait bound `for<'a> _: From<<{closure@$DIR/explicit-reference-cast-unrelated-leaf.rs:18:34: 18:41} as Output<'a>>::Type>` is not satisfied
+  --> $DIR/explicit-reference-cast-unrelated-leaf.rs:18:13
+   |
+LL |     wrapper.do_something_wrapper(|value| ());
+   |             ^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
+   |
+   = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/explicit-reference-cast-unrelated-leaf.rs:18:34: 18:41}`
+help: this trait has no implementations, consider adding one
+  --> $DIR/explicit-reference-cast-unrelated-leaf.rs:1:1
+   |
+LL | trait Output<'a> {
+   | ^^^^^^^^^^^^^^^^
+note: required by a bound in `Wrapper::do_something_wrapper`
+  --> $DIR/explicit-reference-cast-unrelated-leaf.rs:11:20
+   |
+LL |     fn do_something_wrapper<O, F>(self, _: F)
+   |        -------------------- required by a bound in this associated function
+...
+LL |         for<'a> O: From<<F as Output<'a>>::Type>,
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.