about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Kuber <esteban@kuber.com.ar>2021-10-13 16:07:22 +0000
committerEsteban Kuber <esteban@kuber.com.ar>2021-11-20 19:19:34 +0000
commitcecbd7657a80a824bdcf60fb43acc7af000ac2c1 (patch)
tree5bf2d8aff434a406360d36494e14e8faea8673b9
parent9fa165d11b5eeedcf6e04f4812704d7fccf60ed6 (diff)
downloadrust-cecbd7657a80a824bdcf60fb43acc7af000ac2c1.tar.gz
rust-cecbd7657a80a824bdcf60fb43acc7af000ac2c1.zip
Suggest constraining `fn` type params when appropriate
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs72
-rw-r--r--src/test/ui/issues/issue-35677.fixed11
-rw-r--r--src/test/ui/issues/issue-35677.rs3
-rw-r--r--src/test/ui/issues/issue-35677.stderr6
-rw-r--r--src/test/ui/issues/issue-69725.fixed13
-rw-r--r--src/test/ui/issues/issue-69725.rs2
-rw-r--r--src/test/ui/issues/issue-69725.stderr6
7 files changed, 85 insertions, 28 deletions
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index b4508368e26..ca174ed5e84 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -704,27 +704,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             if let (ty::Param(_), ty::PredicateKind::Trait(p)) =
                                 (self_ty.kind(), parent_pred.kind().skip_binder())
                             {
-                                if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() {
-                                    let node = def.did.as_local().map(|def_id| {
+                                let node = match p.trait_ref.self_ty().kind() {
+                                    ty::Param(_) => {
+                                        // Account for `fn` items like in `issue-35677.rs` to
+                                        // suggest restricting its type params.
+                                        let did = self.tcx.hir().body_owner_def_id(hir::BodyId {
+                                            hir_id: self.body_id,
+                                        });
+                                        Some(
+                                            self.tcx
+                                                .hir()
+                                                .get(self.tcx.hir().local_def_id_to_hir_id(did)),
+                                        )
+                                    }
+                                    ty::Adt(def, _) => def.did.as_local().map(|def_id| {
                                         self.tcx
                                             .hir()
                                             .get(self.tcx.hir().local_def_id_to_hir_id(def_id))
-                                    });
-                                    if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
-                                        if let Some(g) = kind.generics() {
-                                            let key = match g.where_clause.predicates {
-                                                [.., pred] => (pred.span().shrink_to_hi(), false),
-                                                [] => (
-                                                    g.where_clause
-                                                        .span_for_predicates_or_empty_place(),
-                                                    true,
-                                                ),
-                                            };
-                                            type_params
-                                                .entry(key)
-                                                .or_insert_with(FxHashSet::default)
-                                                .insert(obligation.to_owned());
-                                        }
+                                    }),
+                                    _ => None,
+                                };
+                                if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
+                                    if let Some(g) = kind.generics() {
+                                        let key = match g.where_clause.predicates {
+                                            [.., pred] => (pred.span().shrink_to_hi(), false),
+                                            [] => (
+                                                g.where_clause.span_for_predicates_or_empty_place(),
+                                                true,
+                                            ),
+                                        };
+                                        type_params
+                                            .entry(key)
+                                            .or_insert_with(FxHashSet::default)
+                                            .insert(obligation.to_owned());
                                     }
                                 }
                             }
@@ -875,19 +887,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .iter()
                         .filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred))
                         .filter_map(|(pred, parent_pred, _cause)| {
-                            format_pred(*pred).map(|(p, self_ty)| match parent_pred {
-                                None => format!("`{}`", &p),
-                                Some(parent_pred) => match format_pred(*parent_pred) {
+                            format_pred(*pred).map(|(p, self_ty)| {
+                                collect_type_param_suggestions(self_ty, pred, &p);
+                                match parent_pred {
                                     None => format!("`{}`", &p),
-                                    Some((parent_p, _)) => {
-                                        collect_type_param_suggestions(self_ty, parent_pred, &p);
-                                        format!("`{}`\nwhich is required by `{}`", p, parent_p)
-                                    }
-                                },
+                                    Some(parent_pred) => match format_pred(*parent_pred) {
+                                        None => format!("`{}`", &p),
+                                        Some((parent_p, _)) => {
+                                            collect_type_param_suggestions(
+                                                self_ty,
+                                                parent_pred,
+                                                &p,
+                                            );
+                                            format!("`{}`\nwhich is required by `{}`", p, parent_p)
+                                        }
+                                    },
+                                }
                             })
                         })
                         .enumerate()
                         .collect::<Vec<(usize, String)>>();
+
                     for ((span, empty_where), obligations) in type_params.into_iter() {
                         restrict_type_params = true;
                         // #74886: Sort here so that the output is always the same.
diff --git a/src/test/ui/issues/issue-35677.fixed b/src/test/ui/issues/issue-35677.fixed
new file mode 100644
index 00000000000..08174d8d8d5
--- /dev/null
+++ b/src/test/ui/issues/issue-35677.fixed
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(dead_code)]
+use std::collections::HashSet;
+use std::hash::Hash;
+
+fn is_subset<T>(this: &HashSet<T>, other: &HashSet<T>) -> bool where T: Eq, T: Hash {
+    this.is_subset(other)
+    //~^ ERROR the method
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-35677.rs b/src/test/ui/issues/issue-35677.rs
index 15d13979062..2cb394386b8 100644
--- a/src/test/ui/issues/issue-35677.rs
+++ b/src/test/ui/issues/issue-35677.rs
@@ -1,4 +1,7 @@
+// run-rustfix
+#![allow(dead_code)]
 use std::collections::HashSet;
+use std::hash::Hash;
 
 fn is_subset<T>(this: &HashSet<T>, other: &HashSet<T>) -> bool {
     this.is_subset(other)
diff --git a/src/test/ui/issues/issue-35677.stderr b/src/test/ui/issues/issue-35677.stderr
index ab59e5d1acf..a2201b946a6 100644
--- a/src/test/ui/issues/issue-35677.stderr
+++ b/src/test/ui/issues/issue-35677.stderr
@@ -1,5 +1,5 @@
 error[E0599]: the method `is_subset` exists for reference `&HashSet<T>`, but its trait bounds were not satisfied
-  --> $DIR/issue-35677.rs:4:10
+  --> $DIR/issue-35677.rs:7:10
    |
 LL |     this.is_subset(other)
    |          ^^^^^^^^^ method cannot be called on `&HashSet<T>` due to unsatisfied trait bounds
@@ -7,6 +7,10 @@ LL |     this.is_subset(other)
    = note: the following trait bounds were not satisfied:
            `T: Eq`
            `T: Hash`
+help: consider restricting the type parameters to satisfy the trait bounds
+   |
+LL | fn is_subset<T>(this: &HashSet<T>, other: &HashSet<T>) -> bool where T: Eq, T: Hash {
+   |                                                                ++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-69725.fixed b/src/test/ui/issues/issue-69725.fixed
new file mode 100644
index 00000000000..d57badcfd8c
--- /dev/null
+++ b/src/test/ui/issues/issue-69725.fixed
@@ -0,0 +1,13 @@
+// run-rustfix
+// aux-build:issue-69725.rs
+#![allow(dead_code)]
+
+extern crate issue_69725;
+use issue_69725::Struct;
+
+fn crash<A>() where A: Clone {
+    let _ = Struct::<A>::new().clone();
+    //~^ ERROR: the method
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-69725.rs b/src/test/ui/issues/issue-69725.rs
index 7c77293945e..9c88969c5cf 100644
--- a/src/test/ui/issues/issue-69725.rs
+++ b/src/test/ui/issues/issue-69725.rs
@@ -1,4 +1,6 @@
+// run-rustfix
 // aux-build:issue-69725.rs
+#![allow(dead_code)]
 
 extern crate issue_69725;
 use issue_69725::Struct;
diff --git a/src/test/ui/issues/issue-69725.stderr b/src/test/ui/issues/issue-69725.stderr
index b1ba89f6cbe..6395bca300c 100644
--- a/src/test/ui/issues/issue-69725.stderr
+++ b/src/test/ui/issues/issue-69725.stderr
@@ -1,5 +1,5 @@
 error[E0599]: the method `clone` exists for struct `Struct<A>`, but its trait bounds were not satisfied
-  --> $DIR/issue-69725.rs:7:32
+  --> $DIR/issue-69725.rs:9:32
    |
 LL |     let _ = Struct::<A>::new().clone();
    |                                ^^^^^ method cannot be called on `Struct<A>` due to unsatisfied trait bounds
@@ -12,6 +12,10 @@ LL | pub struct Struct<A>(A);
    = note: the following trait bounds were not satisfied:
            `A: Clone`
            which is required by `Struct<A>: Clone`
+help: consider restricting the type parameter to satisfy the trait bound
+   |
+LL | fn crash<A>() where A: Clone {
+   |               ++++++++++++++
 
 error: aborting due to previous error