Skip to content

Commit 82078ae

Browse files
Rollup merge of rust-lang#157264 - Dnreikronos:fix/method-suggest-trait-extra-generics-ice, r=chenyukang
diagnostics: Fix ICE building a trait ref in method suggestions Fixes rust-lang#157189 When a method call doesn't resolve, the no-method-found diagnostic probes every trait for one with a same-named method and builds a trait ref for it to spot trait items duplicated across crate versions. It only ever passed the receiver as the single argument, which works only when the trait's one generic is `Self`. Call `.borrow()` on something and the probe finds `Borrow`, whose extra `Borrowed` parameter leaves the args out of step with the trait's generics, so `debug_assert_args_compatible` fires. Same crash when the receiver type isn't known and there are zero args. Now the args come from `GenericArgs::for_item`: the receiver fills `Self` when we have it, fresh inference variables cover the rest.
2 parents ae9d467 + 10f9f14 commit 82078ae

3 files changed

Lines changed: 107 additions & 1 deletion

File tree

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4796,7 +4796,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
47964796
let hir::Node::Expr(rcvr) = self.tcx.hir_node(hir_id) else {
47974797
return false;
47984798
};
4799-
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, rcvr_ty.into_iter());
4799+
// The trait may have generic parameters beyond `Self` (e.g. `Borrow<Borrowed>`), and
4800+
// `rcvr_ty` may even be unknown. We only ever know the receiver type (the `Self` arg),
4801+
// so fill `Self` from `rcvr_ty` when available and the remaining parameters with fresh
4802+
// inference variables; building a `TraitRef` with a partial arg list would otherwise trip
4803+
// `debug_assert_args_compatible` and ICE. See #157189.
4804+
let trait_ref = ty::TraitRef::new_from_args(
4805+
self.tcx,
4806+
trait_def_id,
4807+
ty::GenericArgs::for_item(self.tcx, trait_def_id, |param, _| {
4808+
if param.index == 0
4809+
&& let Some(rcvr_ty) = rcvr_ty
4810+
{
4811+
rcvr_ty.into()
4812+
} else {
4813+
self.var_for_def(rcvr.span, param)
4814+
}
4815+
}),
4816+
);
48004817
let trait_pred = ty::Binder::dummy(ty::TraitPredicate {
48014818
trait_ref,
48024819
polarity: ty::PredicatePolarity::Positive,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//! Regression test for #157189.
2+
//!
3+
//! When a method call fails to resolve, the "trait which provides `<method>` is
4+
//! implemented but not in scope" diagnostic probes all traits for a method of the
5+
//! same name. Here `.borrow()` matches `std::borrow::Borrow::borrow`, and `Borrow`
6+
//! has a generic parameter (`Borrowed`) besides `Self`. Building the trait
7+
//! reference for the diagnostic used to pass only the receiver type as the single
8+
//! argument, which mismatched the trait's generics and ICEd in
9+
//! `debug_assert_args_compatible`. It should just report the error.
10+
11+
trait Foo {
12+
extern "C" fn borrow(&self);
13+
}
14+
15+
struct Bar;
16+
17+
fn main() {
18+
let foo: Box<dyn Fn(bool) -> usize> = Box::new(Bar);
19+
//~^ ERROR expected a `Fn(bool)` closure, found `Bar`
20+
foo.borrow();
21+
//~^ ERROR no method named `borrow` found
22+
foo.take()
23+
//~^ ERROR `Box<dyn Fn(bool) -> usize>` is not an iterator
24+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
error[E0599]: no method named `borrow` found for struct `Box<dyn Fn(bool) -> usize>` in the current scope
2+
--> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:20:9
3+
|
4+
LL | foo.borrow();
5+
| ^^^^^^
6+
|
7+
--> $SRC_DIR/core/src/borrow.rs:LL:COL
8+
|
9+
= note: the method is available for `Box<dyn Fn(bool) -> usize>` here
10+
|
11+
= help: items from traits can only be used if the trait is in scope
12+
help: use parentheses to call this trait object
13+
|
14+
LL | foo(/* bool */).borrow();
15+
| ++++++++++++
16+
help: trait `Borrow` which provides `borrow` is implemented but not in scope; perhaps you want to import it
17+
|
18+
LL + use std::borrow::Borrow;
19+
|
20+
help: there is a method `borrow_mut` with a similar name
21+
|
22+
LL | foo.borrow_mut();
23+
| ++++
24+
25+
error[E0277]: expected a `Fn(bool)` closure, found `Bar`
26+
--> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:18:43
27+
|
28+
LL | let foo: Box<dyn Fn(bool) -> usize> = Box::new(Bar);
29+
| ^^^^^^^^^^^^^ expected an `Fn(bool)` closure, found `Bar`
30+
|
31+
help: the trait `Fn(bool)` is not implemented for `Bar`
32+
--> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:15:1
33+
|
34+
LL | struct Bar;
35+
| ^^^^^^^^^^
36+
= note: required for the cast from `Box<Bar>` to `Box<dyn Fn(bool) -> usize>`
37+
38+
error[E0599]: `Box<dyn Fn(bool) -> usize>` is not an iterator
39+
--> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:22:9
40+
|
41+
LL | foo.take()
42+
| ^^^^
43+
| |
44+
| this is an associated function, not a method
45+
| `Box<dyn Fn(bool) -> usize>` is not an iterator
46+
|
47+
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
48+
= note: the candidate is defined in an impl for the type `Box<T, A>`
49+
= note: the following trait bounds were not satisfied:
50+
`dyn Fn(bool) -> usize: Iterator`
51+
which is required by `Box<dyn Fn(bool) -> usize>: Iterator`
52+
`Box<dyn Fn(bool) -> usize>: Iterator`
53+
which is required by `&mut Box<dyn Fn(bool) -> usize>: Iterator`
54+
`dyn Fn(bool) -> usize: Iterator`
55+
which is required by `&mut dyn Fn(bool) -> usize: Iterator`
56+
help: use associated function syntax instead
57+
|
58+
LL - foo.take()
59+
LL + Box::<dyn Fn(bool) -> usize>::take(foo)
60+
|
61+
62+
error: aborting due to 3 previous errors
63+
64+
Some errors have detailed explanations: E0277, E0599.
65+
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)