Skip to content

Commit ba755a8

Browse files
committed
Account for existing names when suggesting adding a type param
1 parent f26c855 commit ba755a8

File tree

6 files changed

+60
-27
lines changed

6 files changed

+60
-27
lines changed

src/librustc_hir/hir.rs

+23
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,29 @@ impl GenericParam<'hir> {
437437
}
438438
}
439439

440+
pub trait NextTypeParamName {
441+
fn next_type_param_name(&self) -> &'static str;
442+
}
443+
444+
impl NextTypeParamName for &[GenericParam<'_>] {
445+
fn next_type_param_name(&self) -> &'static str {
446+
// This is the whitelist of possible parameter names that we might suggest.
447+
let possible_names = ["T", "U", "V", "X", "Y", "Z", "A", "B", "C", "D", "E", "F", "G"];
448+
let used_names = self
449+
.iter()
450+
.filter_map(|p| match p.name {
451+
ParamName::Plain(ident) => Some(ident.name),
452+
_ => None,
453+
})
454+
.collect::<Vec<_>>();
455+
456+
possible_names
457+
.iter()
458+
.find(|n| !used_names.contains(&Symbol::intern(n)))
459+
.unwrap_or(&"ParamName")
460+
}
461+
}
462+
440463
#[derive(Default)]
441464
pub struct GenericParamCount {
442465
pub lifetimes: usize,

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_hir as hir;
1010
use rustc_hir::def::DefKind;
1111
use rustc_hir::def_id::DefId;
1212
use rustc_hir::intravisit::Visitor;
13-
use rustc_hir::Node;
13+
use rustc_hir::{NextTypeParamName, Node};
1414
use rustc_middle::ty::TypeckTables;
1515
use rustc_middle::ty::{
1616
self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
@@ -210,13 +210,14 @@ fn suggest_restriction(
210210
}
211211
}
212212

213+
let type_param_name = generics.params.next_type_param_name();
213214
// The type param `T: Trait` we will suggest to introduce.
214-
let type_param = format!("{}: {}", "T", name);
215+
let type_param = format!("{}: {}", type_param_name, name);
215216

216217
// FIXME: modify the `trait_ref` instead of string shenanigans.
217218
// Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`.
218219
let pred = trait_ref.without_const().to_predicate().to_string();
219-
let pred = pred.replace(&impl_name, "T");
220+
let pred = pred.replace(&impl_name, type_param_name);
220221
let mut sugg = vec![
221222
match generics
222223
.params
@@ -244,7 +245,7 @@ fn suggest_restriction(
244245
// ^ suggest `where <T as Trait>::A: Bound`
245246
predicate_constraint(generics, pred),
246247
];
247-
sugg.extend(ty_spans.into_iter().map(|s| (s, "T".to_string())));
248+
sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));
248249

249250
// Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`.
250251
err.multipart_suggestion(

src/librustc_typeck/collect.rs

+2-15
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
2929
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
3030
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
3131
use rustc_hir::weak_lang_items;
32-
use rustc_hir::{GenericParamKind, Node, Unsafety};
32+
use rustc_hir::{GenericParamKind, NextTypeParamName, Node, Unsafety};
3333
use rustc_middle::hir::map::blocks::FnLikeNode;
3434
use rustc_middle::hir::map::Map;
3535
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -135,20 +135,7 @@ crate fn placeholder_type_error(
135135
if placeholder_types.is_empty() {
136136
return;
137137
}
138-
// This is the whitelist of possible parameter names that we might suggest.
139-
let possible_names = ["T", "K", "L", "A", "B", "C"];
140-
let used_names = generics
141-
.iter()
142-
.filter_map(|p| match p.name {
143-
hir::ParamName::Plain(ident) => Some(ident.name),
144-
_ => None,
145-
})
146-
.collect::<Vec<_>>();
147-
148-
let type_name = possible_names
149-
.iter()
150-
.find(|n| !used_names.contains(&Symbol::intern(n)))
151-
.unwrap_or(&"ParamName");
138+
let type_name = generics.next_type_param_name();
152139

153140
let mut sugg: Vec<_> =
154141
placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();

src/test/ui/suggestions/impl-trait-with-missing-bounds.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,21 @@ fn baz(t: impl std::fmt::Debug, constraints: impl Iterator) {
2424
}
2525
}
2626

27-
fn bat<T: std::fmt::Debug>(t: T, constraints: impl Iterator) {
27+
fn bat<K, T: std::fmt::Debug>(t: T, constraints: impl Iterator, _: K) {
2828
for constraint in constraints {
2929
qux(t);
3030
qux(constraint);
3131
//~^ ERROR `<impl Iterator as std::iter::Iterator>::Item` doesn't implement `std::fmt::Debug`
3232
}
3333
}
3434

35+
fn bak(constraints: impl Iterator + std::fmt::Debug) {
36+
for constraint in constraints {
37+
qux(constraint);
38+
//~^ ERROR `<impl Iterator + std::fmt::Debug as std::iter::Iterator>::Item` doesn't implement
39+
}
40+
}
41+
3542
fn qux(_: impl std::fmt::Debug) {}
3643

3744
fn main() {}

src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr

+19-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ LL | fn qux(_: impl std::fmt::Debug) {}
2525
= help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator as std::iter::Iterator>::Item`
2626
help: introduce a type parameter with a trait bound instead of using `impl Trait`
2727
|
28-
LL | fn bar<T, T: Iterator>(t: T, constraints: T) where T: std::fmt::Debug, <T as std::iter::Iterator>::Item: std::fmt::Debug {
28+
LL | fn bar<T, U: Iterator>(t: T, constraints: U) where T: std::fmt::Debug, <U as std::iter::Iterator>::Item: std::fmt::Debug {
2929
| ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3030

3131
error[E0277]: `<impl Iterator as std::iter::Iterator>::Item` doesn't implement `std::fmt::Debug`
@@ -55,9 +55,24 @@ LL | fn qux(_: impl std::fmt::Debug) {}
5555
= help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator as std::iter::Iterator>::Item`
5656
help: introduce a type parameter with a trait bound instead of using `impl Trait`
5757
|
58-
LL | fn bat<T: std::fmt::Debug, T: Iterator>(t: T, constraints: T) where <T as std::iter::Iterator>::Item: std::fmt::Debug {
59-
| ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
58+
LL | fn bat<K, T: std::fmt::Debug, U: Iterator>(t: T, constraints: U, _: K) where <U as std::iter::Iterator>::Item: std::fmt::Debug {
59+
| ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6060

61-
error: aborting due to 4 previous errors
61+
error[E0277]: `<impl Iterator + std::fmt::Debug as std::iter::Iterator>::Item` doesn't implement `std::fmt::Debug`
62+
--> $DIR/impl-trait-with-missing-bounds.rs:37:13
63+
|
64+
LL | qux(constraint);
65+
| ^^^^^^^^^^ `<impl Iterator + std::fmt::Debug as std::iter::Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
66+
...
67+
LL | fn qux(_: impl std::fmt::Debug) {}
68+
| --- --------------- required by this bound in `qux`
69+
|
70+
= help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator + std::fmt::Debug as std::iter::Iterator>::Item`
71+
help: introduce a type parameter with a trait bound instead of using `impl Trait`
72+
|
73+
LL | fn bak<T: Iterator + std::fmt::Debug>(constraints: T) where <T as std::iter::Iterator>::Item: std::fmt::Debug {
74+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
75+
76+
error: aborting due to 5 previous errors
6277

6378
For more information about this error, try `rustc --explain E0277`.

src/test/ui/typeck/typeck_type_placeholder_item.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ LL | fn test6_b<T>(_: _, _: T) { }
106106
|
107107
help: use type parameters instead
108108
|
109-
LL | fn test6_b<T, K>(_: K, _: T) { }
109+
LL | fn test6_b<T, U>(_: U, _: T) { }
110110
| ^^^ ^
111111

112112
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
@@ -117,7 +117,7 @@ LL | fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
117117
|
118118
help: use type parameters instead
119119
|
120-
LL | fn test6_c<T, K, L, A, B, C>(_: C, _: (T, K, L, A, B)) { }
120+
LL | fn test6_c<T, K, L, A, B, U>(_: U, _: (T, K, L, A, B)) { }
121121
| ^^^ ^
122122

123123
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
@@ -377,7 +377,7 @@ LL | struct BadStruct2<_, T>(_, T);
377377
|
378378
help: use type parameters instead
379379
|
380-
LL | struct BadStruct2<K, T>(K, T);
380+
LL | struct BadStruct2<U, T>(U, T);
381381
| ^ ^
382382

383383
error[E0121]: the type placeholder `_` is not allowed within types on item signatures

0 commit comments

Comments
 (0)