about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/op.rs106
-rw-r--r--src/test/ui/issues/issue-20005.stderr12
2 files changed, 70 insertions, 48 deletions
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 89a6b98cd8f..b2026266b51 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -10,7 +10,7 @@ use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
 use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
-use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
+use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 
@@ -254,49 +254,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if !lhs_ty.references_error() {
                     let source_map = self.tcx.sess.source_map();
 
-                    let suggest_constraining_param =
-                        |mut err: &mut DiagnosticBuilder<'_>,
-                         missing_trait: &str,
-                         p: ty::ParamTy,
-                         set_output: bool| {
-                            let hir = self.tcx.hir();
-                            let msg =
-                                &format!("`{}` might need a bound for `{}`", lhs_ty, missing_trait);
-                            if let Some(def_id) = hir
-                                .find(hir.get_parent_item(expr.hir_id))
-                                .and_then(|node| node.hir_id())
-                                .and_then(|hir_id| hir.opt_local_def_id(hir_id))
-                            {
-                                let generics = self.tcx.generics_of(def_id);
-                                let param_def_id = generics.type_param(&p, self.tcx).def_id;
-                                if let Some(generics) = hir
-                                    .as_local_hir_id(param_def_id)
-                                    .and_then(|id| hir.find(hir.get_parent_item(id)))
-                                    .as_ref()
-                                    .and_then(|node| node.generics())
-                                {
-                                    let output = if set_output {
-                                        format!("<Output = {}>", rhs_ty)
-                                    } else {
-                                        String::new()
-                                    };
-                                    suggest_constraining_type_param(
-                                        self.tcx,
-                                        generics,
-                                        &mut err,
-                                        &format!("{}", lhs_ty),
-                                        &format!("{}{}", missing_trait, output),
-                                        None,
-                                    );
-                                } else {
-                                    let span = self.tcx.def_span(param_def_id);
-                                    err.span_label(span, msg);
-                                }
-                            } else {
-                                err.note(&msg);
-                            }
-                        };
-
                     match is_assign {
                         IsAssign::Yes => {
                             let mut err = struct_span_err!(
@@ -362,7 +319,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     // concatenation (e.g., "Hello " += "World!"). This means
                                     // we don't want the note in the else clause to be emitted
                                 } else if let ty::Param(p) = lhs_ty.kind {
-                                    suggest_constraining_param(&mut err, missing_trait, p, false);
+                                    suggest_constraining_param(
+                                        self.tcx,
+                                        &mut err,
+                                        lhs_ty,
+                                        rhs_ty,
+                                        &expr,
+                                        missing_trait,
+                                        p,
+                                        false,
+                                    );
                                 } else if !suggested_deref {
                                     suggest_impl_missing(&mut err, lhs_ty, &missing_trait);
                                 }
@@ -514,7 +480,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     // we don't want the note in the else clause to be emitted
                                 } else if let ty::Param(p) = lhs_ty.kind {
                                     suggest_constraining_param(
+                                        self.tcx,
                                         &mut err,
+                                        lhs_ty,
+                                        rhs_ty,
+                                        &expr,
                                         missing_trait,
                                         p,
                                         use_output,
@@ -965,3 +935,49 @@ fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_tra
         }
     }
 }
+
+fn suggest_constraining_param(
+    tcx: TyCtxt<'_>,
+    mut err: &mut DiagnosticBuilder<'_>,
+    lhs_ty: Ty<'_>,
+    rhs_ty: Ty<'_>,
+    expr: &hir::Expr<'_>,
+    missing_trait: &str,
+    p: ty::ParamTy,
+    set_output: bool,
+) {
+    let hir = tcx.hir();
+    let msg = &format!("`{}` might need a bound for `{}`", lhs_ty, missing_trait);
+    // Try to find the def-id and details for the parameter p. We have only the index,
+    // so we have to find the enclosing function's def-id, then look through its declared
+    // generic parameters to get the declaration.
+    if let Some(def_id) = hir
+        .find(hir.get_parent_item(expr.hir_id))
+        .and_then(|node| node.hir_id())
+        .and_then(|hir_id| hir.opt_local_def_id(hir_id))
+    {
+        let generics = tcx.generics_of(def_id);
+        let param_def_id = generics.type_param(&p, tcx).def_id;
+        if let Some(generics) = hir
+            .as_local_hir_id(param_def_id)
+            .and_then(|id| hir.find(hir.get_parent_item(id)))
+            .as_ref()
+            .and_then(|node| node.generics())
+        {
+            let output = if set_output { format!("<Output = {}>", rhs_ty) } else { String::new() };
+            suggest_constraining_type_param(
+                tcx,
+                generics,
+                &mut err,
+                &format!("{}", lhs_ty),
+                &format!("{}{}", missing_trait, output),
+                None,
+            );
+        } else {
+            let span = tcx.def_span(param_def_id);
+            err.span_label(span, msg);
+        }
+    } else {
+        err.note(&msg);
+    }
+}
diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr
index 19ccf707619..f53489a99f3 100644
--- a/src/test/ui/issues/issue-20005.stderr
+++ b/src/test/ui/issues/issue-20005.stderr
@@ -5,12 +5,18 @@ LL | trait From<Src> {
    |            --- required by this bound in `From`
 ...
 LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self> {
-   |                                                 ^^^^^^^^^^- help: consider further restricting `Self`: `, Self: std::marker::Sized`
-   |                                                 |
-   |                                                 doesn't have a size known at compile-time
+   |                                                 ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider further restricting `Self`
+   |
+LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self>, Self: std::marker::Sized  {
+   |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait From<Src: ?Sized> {
+   |               ^^^^^^^^
 
 error: aborting due to previous error