diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index c9ec32159f476..48e1f553900b0 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -4796,7 +4796,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::Node::Expr(rcvr) = self.tcx.hir_node(hir_id) else { return false; }; - let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, rcvr_ty.into_iter()); + // The trait may have generic parameters beyond `Self` (e.g. `Borrow`), and + // `rcvr_ty` may even be unknown. We only ever know the receiver type (the `Self` arg), + // so fill `Self` from `rcvr_ty` when available and the remaining parameters with fresh + // inference variables; building a `TraitRef` with a partial arg list would otherwise trip + // `debug_assert_args_compatible` and ICE. See #157189. + let trait_ref = ty::TraitRef::new_from_args( + self.tcx, + trait_def_id, + ty::GenericArgs::for_item(self.tcx, trait_def_id, |param, _| { + if param.index == 0 + && let Some(rcvr_ty) = rcvr_ty + { + rcvr_ty.into() + } else { + self.var_for_def(rcvr.span, param) + } + }), + ); let trait_pred = ty::Binder::dummy(ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Positive, diff --git a/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.rs b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.rs new file mode 100644 index 0000000000000..0a98cdef5c923 --- /dev/null +++ b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.rs @@ -0,0 +1,24 @@ +//! Regression test for #157189. +//! +//! When a method call fails to resolve, the "trait which provides `` is +//! implemented but not in scope" diagnostic probes all traits for a method of the +//! same name. Here `.borrow()` matches `std::borrow::Borrow::borrow`, and `Borrow` +//! has a generic parameter (`Borrowed`) besides `Self`. Building the trait +//! reference for the diagnostic used to pass only the receiver type as the single +//! argument, which mismatched the trait's generics and ICEd in +//! `debug_assert_args_compatible`. It should just report the error. + +trait Foo { + extern "C" fn borrow(&self); +} + +struct Bar; + +fn main() { + let foo: Box usize> = Box::new(Bar); + //~^ ERROR expected a `Fn(bool)` closure, found `Bar` + foo.borrow(); + //~^ ERROR no method named `borrow` found + foo.take() + //~^ ERROR `Box usize>` is not an iterator +} diff --git a/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.stderr b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.stderr new file mode 100644 index 0000000000000..aa46a41fa3378 --- /dev/null +++ b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.stderr @@ -0,0 +1,65 @@ +error[E0599]: no method named `borrow` found for struct `Box usize>` in the current scope + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:20:9 + | +LL | foo.borrow(); + | ^^^^^^ + | + --> $SRC_DIR/core/src/borrow.rs:LL:COL + | + = note: the method is available for `Box usize>` here + | + = help: items from traits can only be used if the trait is in scope +help: use parentheses to call this trait object + | +LL | foo(/* bool */).borrow(); + | ++++++++++++ +help: trait `Borrow` which provides `borrow` is implemented but not in scope; perhaps you want to import it + | +LL + use std::borrow::Borrow; + | +help: there is a method `borrow_mut` with a similar name + | +LL | foo.borrow_mut(); + | ++++ + +error[E0277]: expected a `Fn(bool)` closure, found `Bar` + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:18:43 + | +LL | let foo: Box usize> = Box::new(Bar); + | ^^^^^^^^^^^^^ expected an `Fn(bool)` closure, found `Bar` + | +help: the trait `Fn(bool)` is not implemented for `Bar` + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:15:1 + | +LL | struct Bar; + | ^^^^^^^^^^ + = note: required for the cast from `Box` to `Box usize>` + +error[E0599]: `Box usize>` is not an iterator + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:22:9 + | +LL | foo.take() + | ^^^^ + | | + | this is an associated function, not a method + | `Box usize>` is not an iterator + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter + = note: the candidate is defined in an impl for the type `Box` + = note: the following trait bounds were not satisfied: + `dyn Fn(bool) -> usize: Iterator` + which is required by `Box usize>: Iterator` + `Box usize>: Iterator` + which is required by `&mut Box usize>: Iterator` + `dyn Fn(bool) -> usize: Iterator` + which is required by `&mut dyn Fn(bool) -> usize: Iterator` +help: use associated function syntax instead + | +LL - foo.take() +LL + Box:: usize>::take(foo) + | + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`.