]> git.lizzy.rs Git - rust.git/commitdiff
Account for existing names when suggesting adding a type param
authorEsteban Küber <esteban@kuber.com.ar>
Sun, 5 Apr 2020 20:13:13 +0000 (13:13 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Sat, 11 Apr 2020 21:34:01 +0000 (14:34 -0700)
src/librustc_hir/hir.rs
src/librustc_trait_selection/traits/error_reporting/suggestions.rs
src/librustc_typeck/collect.rs
src/test/ui/suggestions/impl-trait-with-missing-bounds.rs
src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr
src/test/ui/typeck/typeck_type_placeholder_item.stderr

index b719d576d6f67b632da1992055960183d1aa2883..b4744a7d6db1f1c11f882b592d6979e171f62e8b 100644 (file)
@@ -437,6 +437,29 @@ pub fn bounds_span(&self) -> Option<Span> {
     }
 }
 
+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)]
 pub struct GenericParamCount {
     pub lifetimes: usize,
index 7e210cb7d25ab5d86392d666dd755bb33b3f2e94..16bdfe5d0d1ecfdfa82b5636fb6d5c72ae0517cd 100644 (file)
@@ -10,7 +10,7 @@
 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 `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::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 <T as Trait>::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: Trait>(t: T) where <T as Trait>::A: Bound`.
         err.multipart_suggestion(
index 23bee8e7aad41455747eba56e3ae34d560256718..eb8f46e83bbf5308c05d7eba4d701a46590bd5e1 100644 (file)
@@ -29,7 +29,7 @@
 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 @@ struct CollectItemTypesVisitor<'tcx> {
     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::<Vec<_>>();
-
-    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();
index d831bafa2b51ce321d3821759e796b79f437bc5f..6947bc0a734b9c8ced2e7421aa7572a0a76290c4 100644 (file)
@@ -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 {
         qux(t);
         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 main() {}
index f0f47876ed0f2ec5a98a9d9cc1dc451a3802daf6..2d48be42233eae341fea0c00e10e654884410c38 100644 (file)
@@ -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: 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`
@@ -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: 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`.
index db67e0c9b7d98fa6d1f977ce9e1384c077b787d5..6c0653d5fcb7c64f28458f2cef69b81d33036122 100644 (file)
@@ -106,7 +106,7 @@ LL | fn test6_b<T>(_: _, _: T) { }
    |
 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
@@ -117,7 +117,7 @@ LL | fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
    |
 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
@@ -377,7 +377,7 @@ LL | struct BadStruct2<_, T>(_, T);
    |
 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