diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index b719d576d6f..b4744a7d6db 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -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::>(); + + possible_names + .iter() + .find(|n| !used_names.contains(&Symbol::intern(n))) + .unwrap_or(&"ParamName") + } +} + #[derive(Default)] pub struct GenericParamCount { pub lifetimes: usize, diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 7e210cb7d25..16bdfe5d0d1 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -10,7 +10,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::Node; +use rustc_hir::{NextTypeParamName, Node}; use rustc_middle::ty::TypeckTables; use rustc_middle::ty::{ 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. - let type_param = format!("{}: {}", "T", name); + let type_param = format!("{}: {}", type_param_name, name); // FIXME: modify the `trait_ref` instead of string shenanigans. // Turn `::Bar: Qux` into `::Bar: Qux`. 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![ match generics .params @@ -245,7 +246,7 @@ fn suggest_restriction( // ^ suggest `where ::A: Bound` 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: T) where ::A: Bound`. err.multipart_suggestion( diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 23bee8e7aad..eb8f46e83bb 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -29,7 +29,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; 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::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -135,20 +135,7 @@ crate fn placeholder_type_error( if placeholder_types.is_empty() { return; } - // This is the whitelist of possible parameter names that we might suggest. - 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::>(); - - let type_name = possible_names - .iter() - .find(|n| !used_names.contains(&Symbol::intern(n))) - .unwrap_or(&"ParamName"); + let type_name = generics.next_type_param_name(); let mut sugg: Vec<_> = placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect(); diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs index d831bafa2b5..6947bc0a734 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs @@ -24,7 +24,7 @@ fn baz(t: impl std::fmt::Debug, constraints: impl Iterator) { } } -fn bat(t: T, constraints: impl Iterator) { +fn bat(t: T, constraints: impl Iterator, _: K) { for constraint in constraints { qux(t); qux(constraint); @@ -32,6 +32,13 @@ fn bat(t: T, constraints: impl Iterator) { } } +fn bak(constraints: impl Iterator + std::fmt::Debug) { + for constraint in constraints { + qux(constraint); +//~^ ERROR `::Item` doesn't implement + } +} + fn qux(_: impl std::fmt::Debug) {} fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr index f0f47876ed0..2d48be42233 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr @@ -25,7 +25,7 @@ LL | fn qux(_: impl std::fmt::Debug) {} = help: the trait `std::fmt::Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn bar(t: T, constraints: T) where T: std::fmt::Debug, ::Item: std::fmt::Debug { +LL | fn bar(t: T, constraints: U) where T: std::fmt::Debug, ::Item: std::fmt::Debug { | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `::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 `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn bat(t: T, constraints: T) where ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bat(t: T, constraints: U, _: K) where ::Item: std::fmt::Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error[E0277]: `::Item` doesn't implement `std::fmt::Debug` + --> $DIR/impl-trait-with-missing-bounds.rs:37:13 + | +LL | qux(constraint); + | ^^^^^^^^^^ `::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 `::Item` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | fn bak(constraints: T) where ::Item: std::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index db67e0c9b7d..6c0653d5fcb 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -106,7 +106,7 @@ LL | fn test6_b(_: _, _: T) { } | help: use type parameters instead | -LL | fn test6_b(_: K, _: T) { } +LL | fn test6_b(_: U, _: T) { } | ^^^ ^ 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)) { } | help: use type parameters instead | -LL | fn test6_c(_: C, _: (T, K, L, A, B)) { } +LL | fn test6_c(_: U, _: (T, K, L, A, B)) { } | ^^^ ^ 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 | -LL | struct BadStruct2(K, T); +LL | struct BadStruct2(U, T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures