Skip to content

Commit c40d63c

Browse files
committed
When annotations needed, look at impls for more accurate suggestions
When encountering an expression that needs type annotations, if we have the trait `DefId` we look for all the `impl`s that could be satisfied by the expression we have (without looking at additional obligations) and suggest the fully qualified to specific impls. For left over type parameters, we replace them with `_`. ``` error[E0283]: type annotations needed --> $DIR/E0283.rs:35:24 | LL | let bar = foo_impl.into() * 1u32; | ^^^^ | note: multiple `impl`s satisfying `Impl: Into<_>` found --> $DIR/E0283.rs:17:1 | LL | impl Into<u32> for Impl { | ^^^^^^^^^^^^^^^^^^^^^^^ = note: and another `impl` found in the `core` crate: - impl<T, U> Into<U> for T where U: From<T>; help: try using a fully qualified path to specify the expected types | LL | let bar = <_ as Into<_>>::into(foo_impl) * 1u32; | +++++++++++++++++++++ ~ help: try using a fully qualified path to specify the expected types | LL | let bar = <Impl as Into<u32>>::into(foo_impl) * 1u32; | ++++++++++++++++++++++++++ ~ ``` This approach does not account for blanket-impls, so we can end up with suggestions like `<_ as Into<_>>::into(foo)`. It'd be nice to have a more complete mechanism that does account for all obligations when resolving methods.
1 parent e60ebb2 commit c40d63c

23 files changed

+387
-97
lines changed

compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs

+78-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::errors::{
2525
AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError,
2626
SourceKindMultiSuggestion, SourceKindSubdiag,
2727
};
28-
use crate::infer::InferCtxt;
28+
use crate::infer::{InferCtxt, InferCtxtExt};
2929

3030
pub enum TypeAnnotationNeeded {
3131
/// ```compile_fail,E0282
@@ -557,12 +557,83 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
557557
_ => "",
558558
};
559559

560-
multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
561-
receiver.span,
562-
def_path,
563-
adjustment,
564-
successor,
565-
));
560+
let mut paths = vec![];
561+
let param_env = ty::ParamEnv::reveal_all();
562+
let name = self.infcx.tcx.item_name(def_id);
563+
// Look for all the possible implementations to suggest, otherwise we'll show
564+
// just suggest the syntax for the fully qualified path with placeholders.
565+
self.infcx.tcx.for_each_relevant_impl(
566+
self.infcx.tcx.parent(def_id), // Trait `DefId`
567+
args.type_at(0), // `Self` type
568+
|impl_def_id| {
569+
let impl_args = self.fresh_args_for_item(DUMMY_SP, impl_def_id);
570+
let impl_trait_ref = self
571+
.infcx
572+
.tcx
573+
.impl_trait_ref(impl_def_id)
574+
.unwrap()
575+
.instantiate(self.infcx.tcx, impl_args);
576+
let impl_self_ty = impl_trait_ref.self_ty();
577+
if self.infcx.can_eq(param_env, impl_self_ty, args.type_at(0)) {
578+
// The expr's self type could conform to this impl's self type.
579+
} else {
580+
// Nope, don't bother.
581+
return;
582+
}
583+
let assocs = self.infcx.tcx.associated_items(impl_def_id);
584+
585+
// We're at the `impl` level, but we want to get the same method we
586+
// called *on this `impl`*, in order to get the right DefId and args.
587+
let Some(assoc) = assocs.filter_by_name_unhygienic(name).next() else {
588+
// The method isn't in this `impl`? Not useful to us then.
589+
return;
590+
};
591+
// Let's ignore the generic params and replace them with `_` in the
592+
// suggested path.
593+
let identity_method = ty::GenericArgs::for_item(
594+
self.infcx.tcx,
595+
assoc.def_id,
596+
|param, _| {
597+
// We don't want to name the arguments, we just want to give an
598+
// idea of what the syntax is.
599+
match param.kind {
600+
ty::GenericParamDefKind::Lifetime => {
601+
self.infcx.tcx.lifetimes.re_erased.into()
602+
}
603+
ty::GenericParamDefKind::Type { .. } => {
604+
self.next_ty_var(DUMMY_SP).into()
605+
}
606+
ty::GenericParamDefKind::Const { .. } => {
607+
self.next_const_var(DUMMY_SP).into()
608+
}
609+
}
610+
},
611+
);
612+
let mut printer = fmt_printer(self, Namespace::ValueNS);
613+
printer.print_def_path(assoc.def_id, identity_method).unwrap();
614+
paths.push(printer.into_buffer());
615+
},
616+
);
617+
if paths.len() > 20 || paths.is_empty() {
618+
// This will show the fallback impl, so the expression will have type
619+
// parameter placeholders, but it's better than nothing.
620+
multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
621+
receiver.span,
622+
def_path,
623+
adjustment,
624+
successor,
625+
));
626+
} else {
627+
// These are the paths to specific impls.
628+
for path in paths {
629+
multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
630+
receiver.span,
631+
path,
632+
adjustment,
633+
successor,
634+
));
635+
}
636+
}
566637
}
567638
}
568639
InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {

tests/ui/error-codes/E0283.rs

+1
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,6 @@ fn main() {
3333
fn buzz() {
3434
let foo_impl = Impl::new();
3535
let bar = foo_impl.into() * 1u32; //~ ERROR E0283
36+
// let bar = <Impl as Into<u32>>::into(foo_impl) * 1u32;
3637
foo(bar);
3738
}

tests/ui/error-codes/E0283.stderr

+6-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ LL | impl Into<u32> for Impl {
2828
where U: From<T>;
2929
help: try using a fully qualified path to specify the expected types
3030
|
31-
LL | let bar = <Impl as Into<T>>::into(foo_impl) * 1u32;
32-
| ++++++++++++++++++++++++ ~
31+
LL | let bar = <_ as Into<_>>::into(foo_impl) * 1u32;
32+
| +++++++++++++++++++++ ~
33+
help: try using a fully qualified path to specify the expected types
34+
|
35+
LL | let bar = <Impl as Into<u32>>::into(foo_impl) * 1u32;
36+
| ++++++++++++++++++++++++++ ~
3337

3438
error: aborting due to 2 previous errors
3539

tests/ui/inference/ambiguous_type_parameter.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | InMemoryStore.get_raw(&String::default());
66
|
77
help: try using a fully qualified path to specify the expected types
88
|
9-
LL | <InMemoryStore as Store<String, HashMap<K, String>>>::get_raw(&InMemoryStore, &String::default());
9+
LL | <InMemoryStore as Store<String, HashMap<_, String>>>::get_raw(&InMemoryStore, &String::default());
1010
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ~
1111

1212
error: aborting due to 1 previous error

tests/ui/inference/issue-12028.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | self.input_stream(&mut stream);
77
= note: cannot satisfy `<_ as StreamHasher>::S == <H as StreamHasher>::S`
88
help: try using a fully qualified path to specify the expected types
99
|
10-
LL | <u8 as StreamHash<H>>::input_stream(self, &mut stream);
10+
LL | <u8 as StreamHash<_>>::input_stream(self, &mut stream);
1111
| ++++++++++++++++++++++++++++++++++++ ~
1212

1313
error: aborting due to 1 previous error

tests/ui/inference/issue-70082.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ LL | let y: f64 = 0.01f64 * 1i16.into();
99
= note: cannot satisfy `<f64 as Mul<_>>::Output == f64`
1010
help: try using a fully qualified path to specify the expected types
1111
|
12-
LL | let y: f64 = 0.01f64 * <i16 as Into<T>>::into(1i16);
13-
| +++++++++++++++++++++++ ~
12+
LL | let y: f64 = 0.01f64 * <_ as Into<_>>::into(1i16);
13+
| +++++++++++++++++++++ ~
1414

1515
error: aborting due to 1 previous error
1616

tests/ui/inference/issue-71584.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ LL | d = d % n.into();
99
= note: cannot satisfy `<u64 as Rem<_>>::Output == u64`
1010
help: try using a fully qualified path to specify the expected types
1111
|
12-
LL | d = d % <u32 as Into<T>>::into(n);
13-
| +++++++++++++++++++++++ ~
12+
LL | d = d % <_ as Into<_>>::into(n);
13+
| +++++++++++++++++++++ ~
1414

1515
error: aborting due to 1 previous error
1616

tests/ui/inference/issue-72616.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ LL | if String::from("a") == "a".try_into().unwrap() {}
1313
- impl<'a, 'b> PartialEq<str> for String;
1414
help: try using a fully qualified path to specify the expected types
1515
|
16-
LL | if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
17-
| +++++++++++++++++++++++++++++++ ~
16+
LL | if String::from("a") == <_ as TryInto<_>>::try_into("a").unwrap() {}
17+
| ++++++++++++++++++++++++++++ ~
1818

1919
error[E0283]: type annotations needed
2020
--> $DIR/issue-72616.rs:22:37
@@ -29,8 +29,8 @@ LL | if String::from("a") == "a".try_into().unwrap() {}
2929
= note: required for `&str` to implement `TryInto<_>`
3030
help: try using a fully qualified path to specify the expected types
3131
|
32-
LL | if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
33-
| +++++++++++++++++++++++++++++++ ~
32+
LL | if String::from("a") == <_ as TryInto<_>>::try_into("a").unwrap() {}
33+
| ++++++++++++++++++++++++++++ ~
3434

3535
error: aborting due to 2 previous errors
3636

tests/ui/inference/issue-72690.stderr

+112-16
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,20 @@ LL | String::from("x".as_ref());
2121
- impl AsRef<str> for str;
2222
help: try using a fully qualified path to specify the expected types
2323
|
24-
LL | String::from(<str as AsRef<T>>::as_ref("x"));
25-
| ++++++++++++++++++++++++++ ~
24+
LL | String::from(os_str::<impl AsRef<OsStr> for str>::as_ref("x"));
25+
| ++++++++++++++++++++++++++++++++++++++++++++ ~
26+
help: try using a fully qualified path to specify the expected types
27+
|
28+
LL | String::from(path::<impl AsRef<Path> for str>::as_ref("x"));
29+
| +++++++++++++++++++++++++++++++++++++++++ ~
30+
help: try using a fully qualified path to specify the expected types
31+
|
32+
LL | String::from(<str as AsRef<str>>::as_ref("x"));
33+
| ++++++++++++++++++++++++++++ ~
34+
help: try using a fully qualified path to specify the expected types
35+
|
36+
LL | String::from(core::str::<impl AsRef<[u8]> for str>::as_ref("x"));
37+
| ++++++++++++++++++++++++++++++++++++++++++++++ ~
2638

2739
error[E0283]: type annotations needed
2840
--> $DIR/issue-72690.rs:12:9
@@ -47,8 +59,20 @@ LL | |x| String::from("x".as_ref());
4759
- impl AsRef<str> for str;
4860
help: try using a fully qualified path to specify the expected types
4961
|
50-
LL | |x| String::from(<str as AsRef<T>>::as_ref("x"));
51-
| ++++++++++++++++++++++++++ ~
62+
LL | |x| String::from(os_str::<impl AsRef<OsStr> for str>::as_ref("x"));
63+
| ++++++++++++++++++++++++++++++++++++++++++++ ~
64+
help: try using a fully qualified path to specify the expected types
65+
|
66+
LL | |x| String::from(path::<impl AsRef<Path> for str>::as_ref("x"));
67+
| +++++++++++++++++++++++++++++++++++++++++ ~
68+
help: try using a fully qualified path to specify the expected types
69+
|
70+
LL | |x| String::from(<str as AsRef<str>>::as_ref("x"));
71+
| ++++++++++++++++++++++++++++ ~
72+
help: try using a fully qualified path to specify the expected types
73+
|
74+
LL | |x| String::from(core::str::<impl AsRef<[u8]> for str>::as_ref("x"));
75+
| ++++++++++++++++++++++++++++++++++++++++++++++ ~
5276

5377
error[E0283]: type annotations needed for `&_`
5478
--> $DIR/issue-72690.rs:17:9
@@ -89,8 +113,20 @@ LL | String::from("x".as_ref());
89113
- impl AsRef<str> for str;
90114
help: try using a fully qualified path to specify the expected types
91115
|
92-
LL | String::from(<str as AsRef<T>>::as_ref("x"));
93-
| ++++++++++++++++++++++++++ ~
116+
LL | String::from(os_str::<impl AsRef<OsStr> for str>::as_ref("x"));
117+
| ++++++++++++++++++++++++++++++++++++++++++++ ~
118+
help: try using a fully qualified path to specify the expected types
119+
|
120+
LL | String::from(path::<impl AsRef<Path> for str>::as_ref("x"));
121+
| +++++++++++++++++++++++++++++++++++++++++ ~
122+
help: try using a fully qualified path to specify the expected types
123+
|
124+
LL | String::from(<str as AsRef<str>>::as_ref("x"));
125+
| ++++++++++++++++++++++++++++ ~
126+
help: try using a fully qualified path to specify the expected types
127+
|
128+
LL | String::from(core::str::<impl AsRef<[u8]> for str>::as_ref("x"));
129+
| ++++++++++++++++++++++++++++++++++++++++++++++ ~
94130

95131
error[E0283]: type annotations needed
96132
--> $DIR/issue-72690.rs:28:5
@@ -115,8 +151,20 @@ LL | String::from("x".as_ref());
115151
- impl AsRef<str> for str;
116152
help: try using a fully qualified path to specify the expected types
117153
|
118-
LL | String::from(<str as AsRef<T>>::as_ref("x"));
119-
| ++++++++++++++++++++++++++ ~
154+
LL | String::from(os_str::<impl AsRef<OsStr> for str>::as_ref("x"));
155+
| ++++++++++++++++++++++++++++++++++++++++++++ ~
156+
help: try using a fully qualified path to specify the expected types
157+
|
158+
LL | String::from(path::<impl AsRef<Path> for str>::as_ref("x"));
159+
| +++++++++++++++++++++++++++++++++++++++++ ~
160+
help: try using a fully qualified path to specify the expected types
161+
|
162+
LL | String::from(<str as AsRef<str>>::as_ref("x"));
163+
| ++++++++++++++++++++++++++++ ~
164+
help: try using a fully qualified path to specify the expected types
165+
|
166+
LL | String::from(core::str::<impl AsRef<[u8]> for str>::as_ref("x"));
167+
| ++++++++++++++++++++++++++++++++++++++++++++++ ~
120168

121169
error[E0283]: type annotations needed
122170
--> $DIR/issue-72690.rs:37:5
@@ -141,8 +189,20 @@ LL | String::from("x".as_ref());
141189
- impl AsRef<str> for str;
142190
help: try using a fully qualified path to specify the expected types
143191
|
144-
LL | String::from(<str as AsRef<T>>::as_ref("x"));
145-
| ++++++++++++++++++++++++++ ~
192+
LL | String::from(os_str::<impl AsRef<OsStr> for str>::as_ref("x"));
193+
| ++++++++++++++++++++++++++++++++++++++++++++ ~
194+
help: try using a fully qualified path to specify the expected types
195+
|
196+
LL | String::from(path::<impl AsRef<Path> for str>::as_ref("x"));
197+
| +++++++++++++++++++++++++++++++++++++++++ ~
198+
help: try using a fully qualified path to specify the expected types
199+
|
200+
LL | String::from(<str as AsRef<str>>::as_ref("x"));
201+
| ++++++++++++++++++++++++++++ ~
202+
help: try using a fully qualified path to specify the expected types
203+
|
204+
LL | String::from(core::str::<impl AsRef<[u8]> for str>::as_ref("x"));
205+
| ++++++++++++++++++++++++++++++++++++++++++++++ ~
146206

147207
error[E0283]: type annotations needed
148208
--> $DIR/issue-72690.rs:46:5
@@ -167,8 +227,20 @@ LL | String::from("x".as_ref());
167227
- impl AsRef<str> for str;
168228
help: try using a fully qualified path to specify the expected types
169229
|
170-
LL | String::from(<str as AsRef<T>>::as_ref("x"));
171-
| ++++++++++++++++++++++++++ ~
230+
LL | String::from(os_str::<impl AsRef<OsStr> for str>::as_ref("x"));
231+
| ++++++++++++++++++++++++++++++++++++++++++++ ~
232+
help: try using a fully qualified path to specify the expected types
233+
|
234+
LL | String::from(path::<impl AsRef<Path> for str>::as_ref("x"));
235+
| +++++++++++++++++++++++++++++++++++++++++ ~
236+
help: try using a fully qualified path to specify the expected types
237+
|
238+
LL | String::from(<str as AsRef<str>>::as_ref("x"));
239+
| ++++++++++++++++++++++++++++ ~
240+
help: try using a fully qualified path to specify the expected types
241+
|
242+
LL | String::from(core::str::<impl AsRef<[u8]> for str>::as_ref("x"));
243+
| ++++++++++++++++++++++++++++++++++++++++++++++ ~
172244

173245
error[E0283]: type annotations needed
174246
--> $DIR/issue-72690.rs:53:5
@@ -193,8 +265,20 @@ LL | String::from("x".as_ref());
193265
- impl AsRef<str> for str;
194266
help: try using a fully qualified path to specify the expected types
195267
|
196-
LL | String::from(<str as AsRef<T>>::as_ref("x"));
197-
| ++++++++++++++++++++++++++ ~
268+
LL | String::from(os_str::<impl AsRef<OsStr> for str>::as_ref("x"));
269+
| ++++++++++++++++++++++++++++++++++++++++++++ ~
270+
help: try using a fully qualified path to specify the expected types
271+
|
272+
LL | String::from(path::<impl AsRef<Path> for str>::as_ref("x"));
273+
| +++++++++++++++++++++++++++++++++++++++++ ~
274+
help: try using a fully qualified path to specify the expected types
275+
|
276+
LL | String::from(<str as AsRef<str>>::as_ref("x"));
277+
| ++++++++++++++++++++++++++++ ~
278+
help: try using a fully qualified path to specify the expected types
279+
|
280+
LL | String::from(core::str::<impl AsRef<[u8]> for str>::as_ref("x"));
281+
| ++++++++++++++++++++++++++++++++++++++++++++++ ~
198282

199283
error[E0283]: type annotations needed
200284
--> $DIR/issue-72690.rs:62:5
@@ -219,8 +303,20 @@ LL | String::from("x".as_ref());
219303
- impl AsRef<str> for str;
220304
help: try using a fully qualified path to specify the expected types
221305
|
222-
LL | String::from(<str as AsRef<T>>::as_ref("x"));
223-
| ++++++++++++++++++++++++++ ~
306+
LL | String::from(os_str::<impl AsRef<OsStr> for str>::as_ref("x"));
307+
| ++++++++++++++++++++++++++++++++++++++++++++ ~
308+
help: try using a fully qualified path to specify the expected types
309+
|
310+
LL | String::from(path::<impl AsRef<Path> for str>::as_ref("x"));
311+
| +++++++++++++++++++++++++++++++++++++++++ ~
312+
help: try using a fully qualified path to specify the expected types
313+
|
314+
LL | String::from(<str as AsRef<str>>::as_ref("x"));
315+
| ++++++++++++++++++++++++++++ ~
316+
help: try using a fully qualified path to specify the expected types
317+
|
318+
LL | String::from(core::str::<impl AsRef<[u8]> for str>::as_ref("x"));
319+
| ++++++++++++++++++++++++++++++++++++++++++++++ ~
224320

225321
error: aborting due to 17 previous errors
226322

tests/ui/inference/issue-80816.rs

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub fn foo() {
5050
let guard: Guard<Arc<usize>> = s.load();
5151
//~^ ERROR: type annotations needed
5252
//~| HELP: try using a fully qualified path to specify the expected types
53+
// let guard: Guard<Arc<usize>> = <Arc<ArcSwapAny<Arc<usize>>> as Access<Arc<usize>>>::load(&s);
5354
}
5455

5556
fn main() {}

tests/ui/issues/issue-69683.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | 0u16.foo(b);
77
= note: cannot satisfy `<u8 as Element<_>>::Array == [u8; 3]`
88
help: try using a fully qualified path to specify the expected types
99
|
10-
LL | <u16 as Foo<I>>::foo(0u16, b);
10+
LL | <u16 as Foo<_>>::foo(0u16, b);
1111
| +++++++++++++++++++++ ~
1212

1313
error[E0283]: type annotations needed
@@ -34,7 +34,7 @@ LL | fn foo(self, x: <u8 as Element<I>>::Array);
3434
| --- required by a bound in this associated function
3535
help: try using a fully qualified path to specify the expected types
3636
|
37-
LL | <u16 as Foo<I>>::foo(0u16, b);
37+
LL | <u16 as Foo<_>>::foo(0u16, b);
3838
| +++++++++++++++++++++ ~
3939

4040
error: aborting due to 2 previous errors

0 commit comments

Comments
 (0)