Skip to content

Commit 7c4b476

Browse files
committed
Auto merge of #96347 - estebank:issue-96292, r=compiler-errors
Erase type params when suggesting fully qualified path When suggesting the use of a fully qualified path for a method call that is ambiguous because it has multiple candidates, erase type params in the resulting code, as they would result in an error when applied. We replace them with `_` in the output to rely on inference. There might be cases where this still produces slighlty incomplete suggestions, but it otherwise produces many more errors in relatively common cases. Fix #96292
2 parents 579d268 + a721383 commit 7c4b476

File tree

5 files changed

+96
-15
lines changed

5 files changed

+96
-15
lines changed

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

+31-10
Original file line numberDiff line numberDiff line change
@@ -734,22 +734,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
734734
if !impl_candidates.is_empty() && e.span.contains(span)
735735
&& let Some(expr) = exprs.first()
736736
&& let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind
737-
&& let [path_segment] = path.segments
737+
&& let [_] = path.segments
738738
{
739+
let mut eraser = TypeParamEraser(self.tcx);
739740
let candidate_len = impl_candidates.len();
740-
let suggestions = impl_candidates.iter().map(|candidate| {
741-
format!(
742-
"{}::{}({})",
743-
candidate, segment.ident, path_segment.ident
744-
)
745-
});
746-
err.span_suggestions(
747-
e.span,
741+
let mut suggestions: Vec<_> = impl_candidates.iter().map(|candidate| {
742+
let candidate = candidate.super_fold_with(&mut eraser);
743+
vec![
744+
(expr.span.shrink_to_lo(), format!("{}::{}(", candidate, segment.ident)),
745+
if exprs.len() == 1 {
746+
(expr.span.shrink_to_hi().with_hi(e.span.hi()), ")".to_string())
747+
} else {
748+
(expr.span.shrink_to_hi().with_hi(exprs[1].span.lo()), ", ".to_string())
749+
},
750+
]
751+
}).collect();
752+
suggestions.sort_by(|a, b| a[0].1.cmp(&b[0].1));
753+
err.multipart_suggestions(
748754
&format!(
749755
"use the fully qualified path for the potential candidate{}",
750756
pluralize!(candidate_len),
751757
),
752-
suggestions,
758+
suggestions.into_iter(),
753759
Applicability::MaybeIncorrect,
754760
);
755761
}
@@ -1037,3 +1043,18 @@ impl<'tcx> TypeFolder<'tcx> for ErrTypeParamEraser<'tcx> {
10371043
}
10381044
}
10391045
}
1046+
1047+
/// Replace type parameters with `ty::Infer(ty::Var)` to display `_`.
1048+
struct TypeParamEraser<'tcx>(TyCtxt<'tcx>);
1049+
1050+
impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'tcx> {
1051+
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
1052+
self.0
1053+
}
1054+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
1055+
match t.kind() {
1056+
ty::Param(_) | ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
1057+
_ => t.super_fold_with(self),
1058+
}
1059+
}
1060+
}

src/test/ui/error-codes/E0283.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ LL | let bar = foo_impl.into() * 1u32;
1414
| | |
1515
| | cannot infer type for type parameter `T` declared on the trait `Into`
1616
| this method call resolves to `T`
17-
| help: use the fully qualified path for the potential candidate: `<Impl as Into<u32>>::into(foo_impl)`
1817
|
1918
note: multiple `impl`s satisfying `Impl: Into<_>` found
2019
--> $DIR/E0283.rs:17:1
@@ -24,6 +23,10 @@ LL | impl Into<u32> for Impl {
2423
= note: and another `impl` found in the `core` crate:
2524
- impl<T, U> Into<U> for T
2625
where U: From<T>;
26+
help: use the fully qualified path for the potential candidate
27+
|
28+
LL | let bar = <Impl as Into<u32>>::into(foo_impl) * 1u32;
29+
| ++++++++++++++++++++++++++ ~
2730

2831
error: aborting due to 2 previous errors
2932

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
struct Thing<X>(X);
2+
3+
trait Method<T> {
4+
fn method(self, _: i32) -> T;
5+
}
6+
7+
impl<X> Method<i32> for Thing<X> {
8+
fn method(self, _: i32) -> i32 { 0 }
9+
}
10+
11+
impl<X> Method<u32> for Thing<X> {
12+
fn method(self, _: i32) -> u32 { 0 }
13+
}
14+
15+
fn main() {
16+
let thing = Thing(true);
17+
thing.method(42);
18+
//~^ ERROR type annotations needed
19+
//~| ERROR type annotations needed
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:17:11
3+
|
4+
LL | thing.method(42);
5+
| ------^^^^^^----
6+
| | |
7+
| | cannot infer type for type parameter `T` declared on the trait `Method`
8+
| this method call resolves to `T`
9+
10+
error[E0283]: type annotations needed
11+
--> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:17:11
12+
|
13+
LL | thing.method(42);
14+
| ------^^^^^^----
15+
| | |
16+
| | cannot infer type for type parameter `T` declared on the trait `Method`
17+
| this method call resolves to `T`
18+
|
19+
note: multiple `impl`s satisfying `Thing<bool>: Method<_>` found
20+
--> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:7:1
21+
|
22+
LL | impl<X> Method<i32> for Thing<X> {
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
...
25+
LL | impl<X> Method<u32> for Thing<X> {
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27+
help: use the fully qualified path for the potential candidates
28+
|
29+
LL | <Thing<_> as Method<i32>>::method(thing, 42);
30+
| ++++++++++++++++++++++++++++++++++ ~
31+
LL | <Thing<_> as Method<u32>>::method(thing, 42);
32+
| ++++++++++++++++++++++++++++++++++ ~
33+
34+
error: aborting due to 2 previous errors
35+
36+
Some errors have detailed explanations: E0282, E0283.
37+
For more information about an error, try `rustc --explain E0282`.

src/test/ui/traits/issue-77982.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ LL | opts.get(opt.as_ref());
3737
help: use the fully qualified path for the potential candidates
3838
|
3939
LL | opts.get(<String as AsRef<OsStr>>::as_ref(opt));
40-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40+
| +++++++++++++++++++++++++++++++++ ~
4141
LL | opts.get(<String as AsRef<Path>>::as_ref(opt));
42-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42+
| ++++++++++++++++++++++++++++++++ ~
4343
LL | opts.get(<String as AsRef<[u8]>>::as_ref(opt));
44-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44+
| ++++++++++++++++++++++++++++++++ ~
4545
LL | opts.get(<String as AsRef<str>>::as_ref(opt));
46-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
46+
| +++++++++++++++++++++++++++++++ ~
4747
and 4 other candidates
4848

4949
error[E0283]: type annotations needed

0 commit comments

Comments
 (0)