Account for existing names when suggesting adding a type param
This commit is contained in:
parent
c85fde126e
commit
01169572a2
@ -437,6 +437,29 @@ impl GenericParam<'hir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait NextTypeParamName {
|
||||||
|
fn next_type_param_name(&self) -> &'static str;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NextTypeParamName for &[GenericParam<'_>] {
|
||||||
|
fn next_type_param_name(&self) -> &'static str {
|
||||||
|
// This is the whitelist of possible parameter names that we might suggest.
|
||||||
|
let possible_names = ["T", "U", "V", "X", "Y", "Z", "A", "B", "C", "D", "E", "F", "G"];
|
||||||
|
let used_names = self
|
||||||
|
.iter()
|
||||||
|
.filter_map(|p| match p.name {
|
||||||
|
ParamName::Plain(ident) => Some(ident.name),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
possible_names
|
||||||
|
.iter()
|
||||||
|
.find(|n| !used_names.contains(&Symbol::intern(n)))
|
||||||
|
.unwrap_or(&"ParamName")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct GenericParamCount {
|
pub struct GenericParamCount {
|
||||||
pub lifetimes: usize,
|
pub lifetimes: usize,
|
||||||
|
@ -10,7 +10,7 @@ use rustc_hir as hir;
|
|||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::Node;
|
use rustc_hir::{NextTypeParamName, Node};
|
||||||
use rustc_middle::ty::TypeckTables;
|
use rustc_middle::ty::TypeckTables;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
|
self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
|
||||||
@ -211,13 +211,14 @@ fn suggest_restriction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let type_param_name = generics.params.next_type_param_name();
|
||||||
// The type param `T: Trait` we will suggest to introduce.
|
// The type param `T: Trait` we will suggest to introduce.
|
||||||
let type_param = format!("{}: {}", "T", name);
|
let type_param = format!("{}: {}", type_param_name, name);
|
||||||
|
|
||||||
// FIXME: modify the `trait_ref` instead of string shenanigans.
|
// FIXME: modify the `trait_ref` instead of string shenanigans.
|
||||||
// Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`.
|
// Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`.
|
||||||
let pred = trait_ref.without_const().to_predicate().to_string();
|
let pred = trait_ref.without_const().to_predicate().to_string();
|
||||||
let pred = pred.replace(&impl_name, "T");
|
let pred = pred.replace(&impl_name, type_param_name);
|
||||||
let mut sugg = vec![
|
let mut sugg = vec![
|
||||||
match generics
|
match generics
|
||||||
.params
|
.params
|
||||||
@ -245,7 +246,7 @@ fn suggest_restriction(
|
|||||||
// ^ suggest `where <T as Trait>::A: Bound`
|
// ^ suggest `where <T as Trait>::A: Bound`
|
||||||
predicate_constraint(generics, pred),
|
predicate_constraint(generics, pred),
|
||||||
];
|
];
|
||||||
sugg.extend(ty_spans.into_iter().map(|s| (s, "T".to_string())));
|
sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));
|
||||||
|
|
||||||
// Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`.
|
// Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`.
|
||||||
err.multipart_suggestion(
|
err.multipart_suggestion(
|
||||||
|
@ -29,7 +29,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
|
|||||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||||
use rustc_hir::weak_lang_items;
|
use rustc_hir::weak_lang_items;
|
||||||
use rustc_hir::{GenericParamKind, Node, Unsafety};
|
use rustc_hir::{GenericParamKind, NextTypeParamName, Node, Unsafety};
|
||||||
use rustc_middle::hir::map::blocks::FnLikeNode;
|
use rustc_middle::hir::map::blocks::FnLikeNode;
|
||||||
use rustc_middle::hir::map::Map;
|
use rustc_middle::hir::map::Map;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||||
@ -135,20 +135,7 @@ crate fn placeholder_type_error(
|
|||||||
if placeholder_types.is_empty() {
|
if placeholder_types.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// This is the whitelist of possible parameter names that we might suggest.
|
let type_name = generics.next_type_param_name();
|
||||||
let possible_names = ["T", "K", "L", "A", "B", "C"];
|
|
||||||
let used_names = generics
|
|
||||||
.iter()
|
|
||||||
.filter_map(|p| match p.name {
|
|
||||||
hir::ParamName::Plain(ident) => Some(ident.name),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let type_name = possible_names
|
|
||||||
.iter()
|
|
||||||
.find(|n| !used_names.contains(&Symbol::intern(n)))
|
|
||||||
.unwrap_or(&"ParamName");
|
|
||||||
|
|
||||||
let mut sugg: Vec<_> =
|
let mut sugg: Vec<_> =
|
||||||
placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
|
placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
|
||||||
|
@ -24,7 +24,7 @@ fn baz(t: impl std::fmt::Debug, constraints: impl Iterator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bat<T: std::fmt::Debug>(t: T, constraints: impl Iterator) {
|
fn bat<K, T: std::fmt::Debug>(t: T, constraints: impl Iterator, _: K) {
|
||||||
for constraint in constraints {
|
for constraint in constraints {
|
||||||
qux(t);
|
qux(t);
|
||||||
qux(constraint);
|
qux(constraint);
|
||||||
@ -32,6 +32,13 @@ fn bat<T: std::fmt::Debug>(t: T, constraints: impl Iterator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bak(constraints: impl Iterator + std::fmt::Debug) {
|
||||||
|
for constraint in constraints {
|
||||||
|
qux(constraint);
|
||||||
|
//~^ ERROR `<impl Iterator + std::fmt::Debug as std::iter::Iterator>::Item` doesn't implement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn qux(_: impl std::fmt::Debug) {}
|
fn qux(_: impl std::fmt::Debug) {}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -25,7 +25,7 @@ LL | fn qux(_: impl std::fmt::Debug) {}
|
|||||||
= help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator as std::iter::Iterator>::Item`
|
= help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator as std::iter::Iterator>::Item`
|
||||||
help: introduce a type parameter with a trait bound instead of using `impl Trait`
|
help: introduce a type parameter with a trait bound instead of using `impl Trait`
|
||||||
|
|
|
|
||||||
LL | fn bar<T, T: Iterator>(t: T, constraints: T) where T: std::fmt::Debug, <T as std::iter::Iterator>::Item: std::fmt::Debug {
|
LL | fn bar<T, U: Iterator>(t: T, constraints: U) where T: std::fmt::Debug, <U as std::iter::Iterator>::Item: std::fmt::Debug {
|
||||||
| ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0277]: `<impl Iterator as std::iter::Iterator>::Item` doesn't implement `std::fmt::Debug`
|
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) {}
|
|||||||
= help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator as std::iter::Iterator>::Item`
|
= help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator as std::iter::Iterator>::Item`
|
||||||
help: introduce a type parameter with a trait bound instead of using `impl Trait`
|
help: introduce a type parameter with a trait bound instead of using `impl Trait`
|
||||||
|
|
|
|
||||||
LL | fn bat<T: std::fmt::Debug, T: Iterator>(t: T, constraints: T) where <T as std::iter::Iterator>::Item: std::fmt::Debug {
|
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 {
|
||||||
| ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error[E0277]: `<impl Iterator + std::fmt::Debug as std::iter::Iterator>::Item` doesn't implement `std::fmt::Debug`
|
||||||
|
--> $DIR/impl-trait-with-missing-bounds.rs:37:13
|
||||||
|
|
|
||||||
|
LL | qux(constraint);
|
||||||
|
| ^^^^^^^^^^ `<impl Iterator + std::fmt::Debug as std::iter::Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
||||||
|
...
|
||||||
|
LL | fn qux(_: impl std::fmt::Debug) {}
|
||||||
|
| --- --------------- required by this bound in `qux`
|
||||||
|
|
|
||||||
|
= help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator + std::fmt::Debug as std::iter::Iterator>::Item`
|
||||||
|
help: introduce a type parameter with a trait bound instead of using `impl Trait`
|
||||||
|
|
|
||||||
|
LL | fn bak<T: Iterator + std::fmt::Debug>(constraints: T) where <T as std::iter::Iterator>::Item: std::fmt::Debug {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
@ -106,7 +106,7 @@ LL | fn test6_b<T>(_: _, _: T) { }
|
|||||||
|
|
|
|
||||||
help: use type parameters instead
|
help: use type parameters instead
|
||||||
|
|
|
|
||||||
LL | fn test6_b<T, K>(_: K, _: T) { }
|
LL | fn test6_b<T, U>(_: U, _: T) { }
|
||||||
| ^^^ ^
|
| ^^^ ^
|
||||||
|
|
||||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
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)) { }
|
|||||||
|
|
|
|
||||||
help: use type parameters instead
|
help: use type parameters instead
|
||||||
|
|
|
|
||||||
LL | fn test6_c<T, K, L, A, B, C>(_: C, _: (T, K, L, A, B)) { }
|
LL | fn test6_c<T, K, L, A, B, U>(_: U, _: (T, K, L, A, B)) { }
|
||||||
| ^^^ ^
|
| ^^^ ^
|
||||||
|
|
||||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||||
@ -377,7 +377,7 @@ LL | struct BadStruct2<_, T>(_, T);
|
|||||||
|
|
|
|
||||||
help: use type parameters instead
|
help: use type parameters instead
|
||||||
|
|
|
|
||||||
LL | struct BadStruct2<K, T>(K, T);
|
LL | struct BadStruct2<U, T>(U, T);
|
||||||
| ^ ^
|
| ^ ^
|
||||||
|
|
||||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||||
|
Loading…
x
Reference in New Issue
Block a user