about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs66
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs121
-rw-r--r--compiler/rustc_typeck/src/check/op.rs68
-rw-r--r--src/test/ui/assignment-operator-unimplemented.stderr17
-rw-r--r--src/test/ui/binop/issue-28837.stderr213
-rw-r--r--src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr20
-rw-r--r--src/test/ui/derives/derives-span-PartialEq-enum.stderr20
-rw-r--r--src/test/ui/derives/derives-span-PartialEq-struct.stderr20
-rw-r--r--src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr20
-rw-r--r--src/test/ui/derives/deriving-no-inner-impl-error-message.stderr20
-rw-r--r--src/test/ui/destructuring-assignment/note-unsupported.stderr17
-rw-r--r--src/test/ui/error-festival.stderr17
-rw-r--r--src/test/ui/issues/issue-14091-2.stderr17
-rw-r--r--src/test/ui/issues/issue-31076.rs2
-rw-r--r--src/test/ui/issues/issue-31076.stderr4
-rw-r--r--src/test/ui/issues/issue-3820.stderr17
-rw-r--r--src/test/ui/issues/issue-62375.stderr10
-rw-r--r--src/test/ui/methods/method-call-err-msg.stderr11
-rw-r--r--src/test/ui/never_type/defaulted-never-note.fallback.stderr2
-rw-r--r--src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr2
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr17
-rw-r--r--src/test/ui/span/issue-39018.stderr17
-rw-r--r--src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr8
-rw-r--r--src/test/ui/suggestions/invalid-bin-op.stderr9
-rw-r--r--src/test/ui/type/type-ascription-precedence.stderr17
27 files changed, 667 insertions, 108 deletions
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index f8a476266d6..c9f0b508f59 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2171,10 +2171,26 @@ impl fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
     }
 }
 
+/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
+/// the trait name. That is, it will print `Trait` instead of
+/// `<T as Trait<U>>`.
+#[derive(Copy, Clone, TypeFoldable, Lift)]
+pub struct TraitRefPrintOnlyTraitName<'tcx>(ty::TraitRef<'tcx>);
+
+impl fmt::Debug for TraitRefPrintOnlyTraitName<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, f)
+    }
+}
+
 impl ty::TraitRef<'tcx> {
     pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> {
         TraitRefPrintOnlyTraitPath(self)
     }
+
+    pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> {
+        TraitRefPrintOnlyTraitName(self)
+    }
 }
 
 impl ty::Binder<'tcx, ty::TraitRef<'tcx>> {
@@ -2193,6 +2209,7 @@ forward_display_to_print! {
     ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>,
     ty::Binder<'tcx, ty::TraitRef<'tcx>>,
     ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
     ty::Binder<'tcx, ty::FnSig<'tcx>>,
     ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
     ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
@@ -2255,6 +2272,10 @@ define_print_and_forward_display! {
         p!(print_def_path(self.0.def_id, self.0.substs));
     }
 
+    TraitRefPrintOnlyTraitName<'tcx> {
+        p!(print_def_path(self.0.def_id, &[]));
+    }
+
     ty::ParamTy {
         p!(write("{}", self.name))
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 6447e4cbf2b..88e8df81488 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -521,7 +521,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                     "this error might have been caused by changes to \
                                     Rust's type-inference algorithm (see issue #48950 \
                                     <https://github.com/rust-lang/rust/issues/48950> \
-                                    for more information).",
+                                    for more information)",
                                 );
                                 err.help("did you intend to use the type `()` here instead?");
                             }
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 65b3ceb8698..f0f2470e80a 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -290,29 +290,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )
     }
 
-    /// `lookup_method_in_trait` is used for overloaded operators.
-    /// It does a very narrow slice of what the normal probe/confirm path does.
-    /// In particular, it doesn't really do any probing: it simply constructs
-    /// an obligation for a particular trait with the given self type and checks
-    /// whether that trait is implemented.
-    //
-    // FIXME(#18741): it seems likely that we can consolidate some of this
-    // code with the other method-lookup code. In particular, the second half
-    // of this method is basically the same as confirmation.
-    #[instrument(level = "debug", skip(self, span, opt_input_types))]
-    pub fn lookup_method_in_trait(
+    pub(super) fn obligation_for_method(
         &self,
         span: Span,
-        m_name: Ident,
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         opt_input_types: Option<&[Ty<'tcx>]>,
-    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        debug!(
-            "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})",
-            self_ty, m_name, trait_def_id, opt_input_types
-        );
-
+    ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
+    {
         // Construct a trait-reference `self_ty : Trait<input_tys>`
         let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
             match param.kind {
@@ -332,17 +317,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Construct an obligation
         let poly_trait_ref = ty::Binder::dummy(trait_ref);
-        let obligation = traits::Obligation::misc(
-            span,
-            self.body_id,
-            self.param_env,
-            poly_trait_ref.without_const().to_predicate(self.tcx),
+        (
+            traits::Obligation::misc(
+                span,
+                self.body_id,
+                self.param_env,
+                poly_trait_ref.without_const().to_predicate(self.tcx),
+            ),
+            substs,
+        )
+    }
+
+    /// `lookup_method_in_trait` is used for overloaded operators.
+    /// It does a very narrow slice of what the normal probe/confirm path does.
+    /// In particular, it doesn't really do any probing: it simply constructs
+    /// an obligation for a particular trait with the given self type and checks
+    /// whether that trait is implemented.
+    //
+    // FIXME(#18741): it seems likely that we can consolidate some of this
+    // code with the other method-lookup code. In particular, the second half
+    // of this method is basically the same as confirmation.
+    #[instrument(level = "debug", skip(self, span, opt_input_types))]
+    pub(super) fn lookup_method_in_trait(
+        &self,
+        span: Span,
+        m_name: Ident,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+        opt_input_types: Option<&[Ty<'tcx>]>,
+    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        debug!(
+            "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})",
+            self_ty, m_name, trait_def_id, opt_input_types
         );
 
+        let (obligation, substs) =
+            self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
+
         // Now we want to know if this can be matched
         if !self.predicate_may_hold(&obligation) {
             debug!("--> Cannot match obligation");
-            return None; // Cannot be matched, no such method resolution is possible.
+            // Cannot be matched, no such method resolution is possible.
+            return None;
         }
 
         // Trait must have a method named `m_name` and it should not have
@@ -416,7 +432,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx),
         ));
 
-        let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig };
+        let callee = MethodCallee { def_id, substs, sig: fn_sig };
 
         debug!("callee = {:?}", callee);
 
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index d849e1d5d28..8c7ec219464 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -15,9 +15,9 @@ use rustc_middle::ty::print::with_crate_prefix;
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{source_map, FileName, Span};
+use rustc_span::{source_map, FileName, MultiSpan, Span};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::Obligation;
+use rustc_trait_selection::traits::{FulfillmentError, Obligation};
 
 use std::cmp::Ordering;
 use std::iter;
@@ -969,6 +969,79 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         None
     }
 
+    crate fn note_unmet_impls_on_type(
+        &self,
+        err: &mut rustc_errors::DiagnosticBuilder<'_>,
+        errors: Vec<FulfillmentError<'tcx>>,
+    ) {
+        let all_local_types_needing_impls =
+            errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(pred) => match pred.self_ty().kind() {
+                    ty::Adt(def, _) => def.did.is_local(),
+                    _ => false,
+                },
+                _ => false,
+            });
+        let mut preds: Vec<_> = errors
+            .iter()
+            .filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(pred) => Some(pred),
+                _ => None,
+            })
+            .collect();
+        preds.sort_by_key(|pred| (pred.def_id(), pred.self_ty()));
+        let def_ids = preds
+            .iter()
+            .filter_map(|pred| match pred.self_ty().kind() {
+                ty::Adt(def, _) => Some(def.did),
+                _ => None,
+            })
+            .collect::<FxHashSet<_>>();
+        let sm = self.tcx.sess.source_map();
+        let mut spans: MultiSpan = def_ids
+            .iter()
+            .filter_map(|def_id| {
+                let span = self.tcx.def_span(*def_id);
+                if span.is_dummy() { None } else { Some(sm.guess_head_span(span)) }
+            })
+            .collect::<Vec<_>>()
+            .into();
+
+        for pred in &preds {
+            match pred.self_ty().kind() {
+                ty::Adt(def, _) => {
+                    spans.push_span_label(
+                        sm.guess_head_span(self.tcx.def_span(def.did)),
+                        format!("must implement `{}`", pred.trait_ref.print_only_trait_path()),
+                    );
+                }
+                _ => {}
+            }
+        }
+
+        if all_local_types_needing_impls && spans.primary_span().is_some() {
+            let msg = if preds.len() == 1 {
+                format!(
+                    "an implementation of `{}` might be missing for `{}`",
+                    preds[0].trait_ref.print_only_trait_path(),
+                    preds[0].self_ty()
+                )
+            } else {
+                format!(
+                    "the following type{} would have to `impl` {} required trait{} for this \
+                     operation to be valid",
+                    pluralize!(def_ids.len()),
+                    if def_ids.len() == 1 { "its" } else { "their" },
+                    pluralize!(preds.len()),
+                )
+            };
+            err.span_note(spans, &msg);
+        }
+
+        let preds: Vec<_> = errors.iter().map(|e| (e.obligation.predicate, None)).collect();
+        self.suggest_derive(err, &preds);
+    }
+
     fn suggest_derive(
         &self,
         err: &mut DiagnosticBuilder<'_>,
@@ -1010,7 +1083,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             return Some((
                                 format!("{}", trait_ref.self_ty()),
                                 self.tcx.def_span(adt_def.did),
-                                format!("{}", trait_ref.print_only_trait_path()),
+                                format!("{}", trait_ref.print_only_trait_name()),
                             ));
                         }
                         None
@@ -1033,6 +1106,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 acc
             },
         );
+        let mut traits: Vec<_> = unsatisfied_predicates
+            .iter()
+            .filter_map(|(pred, _)| {
+                let trait_pred =
+                    if let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() {
+                        trait_pred
+                    } else {
+                        return None;
+                    };
+                if let ty::Adt(adt_def, _) = trait_pred.trait_ref.self_ty().kind() {
+                    if !adt_def.did.is_local() {
+                        return None;
+                    }
+                } else {
+                    return None;
+                };
+
+                let did = trait_pred.def_id();
+                let diagnostic_items = self.tcx.diagnostic_items(did.krate);
+
+                if !derivables
+                    .iter()
+                    .any(|trait_derivable| diagnostic_items.get(trait_derivable) == Some(&did))
+                {
+                    Some(self.tcx.def_span(did))
+                } else {
+                    None
+                }
+            })
+            .collect();
+        traits.sort();
+        traits.dedup();
+
+        let len = traits.len();
+        if len > 0 {
+            let span: MultiSpan = traits.into();
+            err.span_note(
+                span,
+                &format!("the following trait{} must be implemented", pluralize!(len),),
+            );
+        }
+
         for (self_name, self_span, traits) in &derives_grouped {
             err.span_suggestion_verbose(
                 self_span.shrink_to_lo(),
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index d0a32420df3..79e004a47db 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -18,6 +18,7 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
 
 use std::ops::ControlFlow;
 
@@ -257,12 +258,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 method.sig.output()
             }
             // error types are considered "builtin"
-            Err(()) if lhs_ty.references_error() || rhs_ty.references_error() => {
-                self.tcx.ty_error()
-            }
-            Err(()) => {
+            Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(),
+            Err(errors) => {
                 let source_map = self.tcx.sess.source_map();
-                let (mut err, missing_trait, use_output, involves_fn) = match is_assign {
+                let (mut err, missing_trait, use_output) = match is_assign {
                     IsAssign::Yes => {
                         let mut err = struct_span_err!(
                             self.tcx.sess,
@@ -289,7 +288,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             hir::BinOpKind::Shr => Some("std::ops::ShrAssign"),
                             _ => None,
                         };
-                        (err, missing_trait, false, false)
+                        self.note_unmet_impls_on_type(&mut err, errors);
+                        (err, missing_trait, false)
                     }
                     IsAssign::No => {
                         let (message, missing_trait, use_output) = match op.node {
@@ -376,9 +376,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         };
                         let mut err =
                             struct_span_err!(self.tcx.sess, op.span, E0369, "{}", message.as_str());
-                        let mut involves_fn = false;
                         if !lhs_expr.span.eq(&rhs_expr.span) {
-                            involves_fn |= self.add_type_neq_err_label(
+                            self.add_type_neq_err_label(
                                 &mut err,
                                 lhs_expr.span,
                                 lhs_ty,
@@ -386,7 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 op,
                                 is_assign,
                             );
-                            involves_fn |= self.add_type_neq_err_label(
+                            self.add_type_neq_err_label(
                                 &mut err,
                                 rhs_expr.span,
                                 rhs_ty,
@@ -395,10 +394,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 is_assign,
                             );
                         }
-                        (err, missing_trait, use_output, involves_fn)
+                        self.note_unmet_impls_on_type(&mut err, errors);
+                        (err, missing_trait, use_output)
                     }
                 };
-                let mut suggested_deref = false;
                 if let Ref(_, rty, _) = lhs_ty.kind() {
                     if {
                         self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span)
@@ -423,7 +422,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 "*".to_string(),
                                 rustc_errors::Applicability::MachineApplicable,
                             );
-                            suggested_deref = true;
                         }
                     }
                 }
@@ -474,8 +472,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         } else {
                             bug!("type param visitor stored a non type param: {:?}", ty.kind());
                         }
-                    } else if !suggested_deref && !involves_fn {
-                        suggest_impl_missing(&mut err, lhs_ty, missing_trait);
                     }
                 }
                 err.emit();
@@ -665,7 +661,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.write_method_call(ex.hir_id, method);
                 method.sig.output()
             }
-            Err(()) => {
+            Err(errors) => {
                 let actual = self.resolve_vars_if_possible(operand_ty);
                 if !actual.references_error() {
                     let mut err = struct_span_err!(
@@ -720,12 +716,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             Str | Never | Char | Tuple(_) | Array(_, _) => {}
                             Ref(_, lty, _) if *lty.kind() == Str => {}
                             _ => {
-                                let missing_trait = match op {
-                                    hir::UnOp::Neg => "std::ops::Neg",
-                                    hir::UnOp::Not => "std::ops::Not",
-                                    hir::UnOp::Deref => "std::ops::UnDerf",
-                                };
-                                suggest_impl_missing(&mut err, operand_ty, missing_trait);
+                                self.note_unmet_impls_on_type(&mut err, errors);
                             }
                         }
                     }
@@ -741,7 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         lhs_ty: Ty<'tcx>,
         other_tys: &[Ty<'tcx>],
         op: Op,
-    ) -> Result<MethodCallee<'tcx>, ()> {
+    ) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> {
         let lang = self.tcx.lang_items();
 
         let span = match op {
@@ -820,22 +811,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Op::Unary(..) => 0,
             },
         ) {
-            return Err(());
+            return Err(vec![]);
         }
 
+        let opname = Ident::with_dummy_span(opname);
         let method = trait_did.and_then(|trait_did| {
-            let opname = Ident::with_dummy_span(opname);
             self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys))
         });
 
-        match method {
-            Some(ok) => {
+        match (method, trait_did) {
+            (Some(ok), _) => {
                 let method = self.register_infer_ok_obligations(ok);
                 self.select_obligations_where_possible(false, |_| {});
-
                 Ok(method)
             }
-            None => Err(()),
+            (None, None) => Err(vec![]),
+            (None, Some(trait_did)) => {
+                let (obligation, _) =
+                    self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys));
+                let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
+                fulfill.register_predicate_obligation(self, obligation);
+                Err(match fulfill.select_where_possible(&self.infcx) {
+                    Err(errors) => errors,
+                    _ => vec![],
+                })
+            }
         }
     }
 }
@@ -962,18 +962,6 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
     }
 }
 
-/// If applicable, note that an implementation of `trait` for `ty` may fix the error.
-fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_trait: &str) {
-    if let Adt(def, _) = ty.peel_refs().kind() {
-        if def.did.is_local() {
-            err.note(&format!(
-                "an implementation of `{}` might be missing for `{}`",
-                missing_trait, ty
-            ));
-        }
-    }
-}
-
 fn suggest_constraining_param(
     tcx: TyCtxt<'_>,
     body_id: hir::HirId,
diff --git a/src/test/ui/assignment-operator-unimplemented.stderr b/src/test/ui/assignment-operator-unimplemented.stderr
index 5304b09de5e..73c9f86e002 100644
--- a/src/test/ui/assignment-operator-unimplemented.stderr
+++ b/src/test/ui/assignment-operator-unimplemented.stderr
@@ -6,7 +6,22 @@ LL |   a += *b;
    |   |
    |   cannot use `+=` on type `Foo`
    |
-   = note: an implementation of `std::ops::AddAssign` might be missing for `Foo`
+note: an implementation of `AddAssign<_>` might be missing for `Foo`
+  --> $DIR/assignment-operator-unimplemented.rs:1:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^^ must implement `AddAssign<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait AddAssign<Rhs = Self> {
+LL | |     /// Performs the `+=` operation.
+LL | |     ///
+LL | |     /// # Example
+...  |
+LL | |     fn add_assign(&mut self, rhs: Rhs);
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/binop/issue-28837.stderr b/src/test/ui/binop/issue-28837.stderr
index 07f67bc3de7..10f243bab15 100644
--- a/src/test/ui/binop/issue-28837.stderr
+++ b/src/test/ui/binop/issue-28837.stderr
@@ -6,7 +6,22 @@ LL |     a + a;
    |     |
    |     A
    |
-   = note: an implementation of `std::ops::Add` might be missing for `A`
+note: an implementation of `Add<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `Add<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Add<Rhs = Self> {
+LL | |     /// The resulting type after applying the `+` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn add(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0369]: cannot subtract `A` from `A`
   --> $DIR/issue-28837.rs:8:7
@@ -16,7 +31,22 @@ LL |     a - a;
    |     |
    |     A
    |
-   = note: an implementation of `std::ops::Sub` might be missing for `A`
+note: an implementation of `Sub<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `Sub<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Sub<Rhs = Self> {
+LL | |     /// The resulting type after applying the `-` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn sub(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0369]: cannot multiply `A` by `A`
   --> $DIR/issue-28837.rs:10:7
@@ -26,7 +56,22 @@ LL |     a * a;
    |     |
    |     A
    |
-   = note: an implementation of `std::ops::Mul` might be missing for `A`
+note: an implementation of `Mul<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `Mul<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Mul<Rhs = Self> {
+LL | |     /// The resulting type after applying the `*` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn mul(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0369]: cannot divide `A` by `A`
   --> $DIR/issue-28837.rs:12:7
@@ -36,7 +81,22 @@ LL |     a / a;
    |     |
    |     A
    |
-   = note: an implementation of `std::ops::Div` might be missing for `A`
+note: an implementation of `Div<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `Div<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Div<Rhs = Self> {
+LL | |     /// The resulting type after applying the `/` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn div(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0369]: cannot mod `A` by `A`
   --> $DIR/issue-28837.rs:14:7
@@ -46,7 +106,22 @@ LL |     a % a;
    |     |
    |     A
    |
-   = note: an implementation of `std::ops::Rem` might be missing for `A`
+note: an implementation of `Rem<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `Rem<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Rem<Rhs = Self> {
+LL | |     /// The resulting type after applying the `%` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn rem(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0369]: no implementation for `A & A`
   --> $DIR/issue-28837.rs:16:7
@@ -56,7 +131,22 @@ LL |     a & a;
    |     |
    |     A
    |
-   = note: an implementation of `std::ops::BitAnd` might be missing for `A`
+note: an implementation of `BitAnd<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `BitAnd<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
+   |
+LL | / pub trait BitAnd<Rhs = Self> {
+LL | |     /// The resulting type after applying the `&` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn bitand(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0369]: no implementation for `A | A`
   --> $DIR/issue-28837.rs:18:7
@@ -66,7 +156,22 @@ LL |     a | a;
    |     |
    |     A
    |
-   = note: an implementation of `std::ops::BitOr` might be missing for `A`
+note: an implementation of `BitOr<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `BitOr<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
+   |
+LL | / pub trait BitOr<Rhs = Self> {
+LL | |     /// The resulting type after applying the `|` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn bitor(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0369]: no implementation for `A << A`
   --> $DIR/issue-28837.rs:20:7
@@ -76,7 +181,22 @@ LL |     a << a;
    |     |
    |     A
    |
-   = note: an implementation of `std::ops::Shl` might be missing for `A`
+note: an implementation of `Shl<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `Shl<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
+   |
+LL | / pub trait Shl<Rhs = Self> {
+LL | |     /// The resulting type after applying the `<<` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn shl(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0369]: no implementation for `A >> A`
   --> $DIR/issue-28837.rs:22:7
@@ -86,7 +206,22 @@ LL |     a >> a;
    |     |
    |     A
    |
-   = note: an implementation of `std::ops::Shr` might be missing for `A`
+note: an implementation of `Shr<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `Shr<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
+   |
+LL | / pub trait Shr<Rhs = Self> {
+LL | |     /// The resulting type after applying the `>>` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn shr(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0369]: binary operation `==` cannot be applied to type `A`
   --> $DIR/issue-28837.rs:24:7
@@ -96,7 +231,15 @@ LL |     a == a;
    |     |
    |     A
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `A`
+note: an implementation of `PartialEq<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `PartialEq<_>`
+help: consider annotating `A` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error[E0369]: binary operation `!=` cannot be applied to type `A`
   --> $DIR/issue-28837.rs:26:7
@@ -106,7 +249,15 @@ LL |     a != a;
    |     |
    |     A
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `A`
+note: an implementation of `PartialEq<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `PartialEq<_>`
+help: consider annotating `A` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error[E0369]: binary operation `<` cannot be applied to type `A`
   --> $DIR/issue-28837.rs:28:7
@@ -116,7 +267,15 @@ LL |     a < a;
    |     |
    |     A
    |
-   = note: an implementation of `std::cmp::PartialOrd` might be missing for `A`
+note: an implementation of `PartialOrd<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `PartialOrd<_>`
+help: consider annotating `A` with `#[derive(PartialOrd)]`
+   |
+LL | #[derive(PartialOrd)]
+   |
 
 error[E0369]: binary operation `<=` cannot be applied to type `A`
   --> $DIR/issue-28837.rs:30:7
@@ -126,7 +285,15 @@ LL |     a <= a;
    |     |
    |     A
    |
-   = note: an implementation of `std::cmp::PartialOrd` might be missing for `A`
+note: an implementation of `PartialOrd<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `PartialOrd<_>`
+help: consider annotating `A` with `#[derive(PartialOrd)]`
+   |
+LL | #[derive(PartialOrd)]
+   |
 
 error[E0369]: binary operation `>` cannot be applied to type `A`
   --> $DIR/issue-28837.rs:32:7
@@ -136,7 +303,15 @@ LL |     a > a;
    |     |
    |     A
    |
-   = note: an implementation of `std::cmp::PartialOrd` might be missing for `A`
+note: an implementation of `PartialOrd<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `PartialOrd<_>`
+help: consider annotating `A` with `#[derive(PartialOrd)]`
+   |
+LL | #[derive(PartialOrd)]
+   |
 
 error[E0369]: binary operation `>=` cannot be applied to type `A`
   --> $DIR/issue-28837.rs:34:7
@@ -146,7 +321,15 @@ LL |     a >= a;
    |     |
    |     A
    |
-   = note: an implementation of `std::cmp::PartialOrd` might be missing for `A`
+note: an implementation of `PartialOrd<_>` might be missing for `A`
+  --> $DIR/issue-28837.rs:1:1
+   |
+LL | struct A;
+   | ^^^^^^^^^ must implement `PartialOrd<_>`
+help: consider annotating `A` with `#[derive(PartialOrd)]`
+   |
+LL | #[derive(PartialOrd)]
+   |
 
 error: aborting due to 15 previous errors
 
diff --git a/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr
index abcba6da8aa..19d2425ff23 100644
--- a/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr
+++ b/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr
@@ -7,8 +7,16 @@ LL | #[derive(PartialEq)]
 LL |      x: Error
    |      ^^^^^^^^
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `Error`
+note: an implementation of `PartialEq<_>` might be missing for `Error`
+  --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:4:1
+   |
+LL | struct Error;
+   | ^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `Error` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error[E0369]: binary operation `!=` cannot be applied to type `Error`
   --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:9:6
@@ -19,8 +27,16 @@ LL | #[derive(PartialEq)]
 LL |      x: Error
    |      ^^^^^^^^
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `Error`
+note: an implementation of `PartialEq<_>` might be missing for `Error`
+  --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:4:1
+   |
+LL | struct Error;
+   | ^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `Error` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/derives/derives-span-PartialEq-enum.stderr b/src/test/ui/derives/derives-span-PartialEq-enum.stderr
index cdb40c39f16..419832817ca 100644
--- a/src/test/ui/derives/derives-span-PartialEq-enum.stderr
+++ b/src/test/ui/derives/derives-span-PartialEq-enum.stderr
@@ -7,8 +7,16 @@ LL | #[derive(PartialEq)]
 LL |      Error
    |      ^^^^^
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `Error`
+note: an implementation of `PartialEq<_>` might be missing for `Error`
+  --> $DIR/derives-span-PartialEq-enum.rs:4:1
+   |
+LL | struct Error;
+   | ^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `Error` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error[E0369]: binary operation `!=` cannot be applied to type `Error`
   --> $DIR/derives-span-PartialEq-enum.rs:9:6
@@ -19,8 +27,16 @@ LL | #[derive(PartialEq)]
 LL |      Error
    |      ^^^^^
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `Error`
+note: an implementation of `PartialEq<_>` might be missing for `Error`
+  --> $DIR/derives-span-PartialEq-enum.rs:4:1
+   |
+LL | struct Error;
+   | ^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `Error` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/derives/derives-span-PartialEq-struct.stderr b/src/test/ui/derives/derives-span-PartialEq-struct.stderr
index 4cf8851a098..0000f882542 100644
--- a/src/test/ui/derives/derives-span-PartialEq-struct.stderr
+++ b/src/test/ui/derives/derives-span-PartialEq-struct.stderr
@@ -7,8 +7,16 @@ LL | struct Struct {
 LL |     x: Error
    |     ^^^^^^^^
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `Error`
+note: an implementation of `PartialEq<_>` might be missing for `Error`
+  --> $DIR/derives-span-PartialEq-struct.rs:4:1
+   |
+LL | struct Error;
+   | ^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `Error` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error[E0369]: binary operation `!=` cannot be applied to type `Error`
   --> $DIR/derives-span-PartialEq-struct.rs:8:5
@@ -19,8 +27,16 @@ LL | struct Struct {
 LL |     x: Error
    |     ^^^^^^^^
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `Error`
+note: an implementation of `PartialEq<_>` might be missing for `Error`
+  --> $DIR/derives-span-PartialEq-struct.rs:4:1
+   |
+LL | struct Error;
+   | ^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `Error` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr b/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr
index 66bc1687353..07fa900a8c8 100644
--- a/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr
+++ b/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr
@@ -7,8 +7,16 @@ LL | struct Struct(
 LL |     Error
    |     ^^^^^
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `Error`
+note: an implementation of `PartialEq<_>` might be missing for `Error`
+  --> $DIR/derives-span-PartialEq-tuple-struct.rs:4:1
+   |
+LL | struct Error;
+   | ^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `Error` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error[E0369]: binary operation `!=` cannot be applied to type `Error`
   --> $DIR/derives-span-PartialEq-tuple-struct.rs:8:5
@@ -19,8 +27,16 @@ LL | struct Struct(
 LL |     Error
    |     ^^^^^
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `Error`
+note: an implementation of `PartialEq<_>` might be missing for `Error`
+  --> $DIR/derives-span-PartialEq-tuple-struct.rs:4:1
+   |
+LL | struct Error;
+   | ^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `Error` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr
index b97f87da4bf..e322db97fab 100644
--- a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr
+++ b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr
@@ -7,8 +7,16 @@ LL | struct E {
 LL |     x: NoCloneOrEq
    |     ^^^^^^^^^^^^^^
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `NoCloneOrEq`
+note: an implementation of `PartialEq<_>` might be missing for `NoCloneOrEq`
+  --> $DIR/deriving-no-inner-impl-error-message.rs:1:1
+   |
+LL | struct NoCloneOrEq;
+   | ^^^^^^^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `NoCloneOrEq` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error[E0369]: binary operation `!=` cannot be applied to type `NoCloneOrEq`
   --> $DIR/deriving-no-inner-impl-error-message.rs:5:5
@@ -19,8 +27,16 @@ LL | struct E {
 LL |     x: NoCloneOrEq
    |     ^^^^^^^^^^^^^^
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `NoCloneOrEq`
+note: an implementation of `PartialEq<_>` might be missing for `NoCloneOrEq`
+  --> $DIR/deriving-no-inner-impl-error-message.rs:1:1
+   |
+LL | struct NoCloneOrEq;
+   | ^^^^^^^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `NoCloneOrEq` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error[E0277]: the trait bound `NoCloneOrEq: Clone` is not satisfied
   --> $DIR/deriving-no-inner-impl-error-message.rs:10:5
diff --git a/src/test/ui/destructuring-assignment/note-unsupported.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr
index a81324b99e5..7b9788ca0fe 100644
--- a/src/test/ui/destructuring-assignment/note-unsupported.stderr
+++ b/src/test/ui/destructuring-assignment/note-unsupported.stderr
@@ -99,7 +99,22 @@ LL |     S { x: a, y: b } += s;
    |     |
    |     cannot use `+=` on type `S`
    |
-   = note: an implementation of `std::ops::AddAssign` might be missing for `S`
+note: an implementation of `AddAssign<_>` might be missing for `S`
+  --> $DIR/note-unsupported.rs:1:1
+   |
+LL | struct S { x: u8, y: u8 }
+   | ^^^^^^^^ must implement `AddAssign<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait AddAssign<Rhs = Self> {
+LL | |     /// Performs the `+=` operation.
+LL | |     ///
+LL | |     /// # Example
+...  |
+LL | |     fn add_assign(&mut self, rhs: Rhs);
+LL | | }
+   | |_^
 
 error[E0067]: invalid left-hand side of assignment
   --> $DIR/note-unsupported.rs:17:22
diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr
index 89a9d965de2..b8cd7b7464a 100644
--- a/src/test/ui/error-festival.stderr
+++ b/src/test/ui/error-festival.stderr
@@ -36,7 +36,22 @@ error[E0600]: cannot apply unary operator `!` to type `Question`
 LL |     !Question::Yes;
    |     ^^^^^^^^^^^^^^ cannot apply unary operator `!`
    |
-   = note: an implementation of `std::ops::Not` might be missing for `Question`
+note: an implementation of `Not` might be missing for `Question`
+  --> $DIR/error-festival.rs:1:1
+   |
+LL | enum Question {
+   | ^^^^^^^^^^^^^ must implement `Not`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
+   |
+LL | / pub trait Not {
+LL | |     /// The resulting type after applying the `!` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn not(self) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/error-festival.rs:25:5
diff --git a/src/test/ui/issues/issue-14091-2.stderr b/src/test/ui/issues/issue-14091-2.stderr
index acf837d0f76..0b1cc9c7684 100644
--- a/src/test/ui/issues/issue-14091-2.stderr
+++ b/src/test/ui/issues/issue-14091-2.stderr
@@ -4,7 +4,22 @@ error[E0600]: cannot apply unary operator `!` to type `BytePos`
 LL |     assert!(x, x);
    |     ^^^^^^^^^^^^^^ cannot apply unary operator `!`
    |
-   = note: an implementation of `std::ops::Not` might be missing for `BytePos`
+note: an implementation of `Not` might be missing for `BytePos`
+  --> $DIR/issue-14091-2.rs:6:1
+   |
+LL | pub struct BytePos(pub u32);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `Not`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
+   |
+LL | / pub trait Not {
+LL | |     /// The resulting type after applying the `!` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn not(self) -> Self::Output;
+LL | | }
+   | |_^
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-31076.rs b/src/test/ui/issues/issue-31076.rs
index f9c35526ec3..cdb196d4ff2 100644
--- a/src/test/ui/issues/issue-31076.rs
+++ b/src/test/ui/issues/issue-31076.rs
@@ -11,7 +11,7 @@ impl Add<i32> for i32 {}
 
 fn main() {
     let x = 5 + 6;
-    //~^ ERROR cannot add `{integer}` to `{integer}`
+    //~^ ERROR cannot add `i32` to `{integer}`
     let y = 5i32 + 6i32;
     //~^ ERROR cannot add `i32` to `i32`
 }
diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/issues/issue-31076.stderr
index 4c0e1cf7ebb..ac0d9dc7528 100644
--- a/src/test/ui/issues/issue-31076.stderr
+++ b/src/test/ui/issues/issue-31076.stderr
@@ -1,8 +1,8 @@
-error[E0369]: cannot add `{integer}` to `{integer}`
+error[E0369]: cannot add `i32` to `{integer}`
   --> $DIR/issue-31076.rs:13:15
    |
 LL |     let x = 5 + 6;
-   |             - ^ - {integer}
+   |             - ^ - i32
    |             |
    |             {integer}
 
diff --git a/src/test/ui/issues/issue-3820.stderr b/src/test/ui/issues/issue-3820.stderr
index 84f8f9bd147..d5c24e1bb6c 100644
--- a/src/test/ui/issues/issue-3820.stderr
+++ b/src/test/ui/issues/issue-3820.stderr
@@ -6,7 +6,22 @@ LL |     let w = u * 3;
    |             |
    |             Thing
    |
-   = note: an implementation of `std::ops::Mul` might be missing for `Thing`
+note: an implementation of `Mul<_>` might be missing for `Thing`
+  --> $DIR/issue-3820.rs:1:1
+   |
+LL | struct Thing {
+   | ^^^^^^^^^^^^ must implement `Mul<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Mul<Rhs = Self> {
+LL | |     /// The resulting type after applying the `*` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn mul(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-62375.stderr b/src/test/ui/issues/issue-62375.stderr
index 6db45630b94..478e025bed2 100644
--- a/src/test/ui/issues/issue-62375.stderr
+++ b/src/test/ui/issues/issue-62375.stderr
@@ -6,7 +6,15 @@ LL |     a == A::Value;
    |     |
    |     A
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `A`
+note: an implementation of `PartialEq<_>` might be missing for `A`
+  --> $DIR/issue-62375.rs:1:1
+   |
+LL | enum A {
+   | ^^^^^^ must implement `PartialEq<_>`
+help: consider annotating `A` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr
index ffeacfe15dd..c1183e053eb 100644
--- a/src/test/ui/methods/method-call-err-msg.stderr
+++ b/src/test/ui/methods/method-call-err-msg.stderr
@@ -55,6 +55,17 @@ LL |      .take()
    = note: the following trait bounds were not satisfied:
            `Foo: Iterator`
            which is required by `&mut Foo: Iterator`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL | / pub trait Iterator {
+LL | |     /// The type of the elements being iterated over.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Item;
+...  |
+LL | |     }
+LL | | }
+   | |_^
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `take`, perhaps you need to implement it:
            candidate #1: `Iterator`
diff --git a/src/test/ui/never_type/defaulted-never-note.fallback.stderr b/src/test/ui/never_type/defaulted-never-note.fallback.stderr
index a51edb1f09a..b105f03f81c 100644
--- a/src/test/ui/never_type/defaulted-never-note.fallback.stderr
+++ b/src/test/ui/never_type/defaulted-never-note.fallback.stderr
@@ -5,7 +5,7 @@ LL |     foo(_x);
    |     ^^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!`
    |
    = note: this trait is implemented for `()`
-   = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information).
+   = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information)
    = help: did you intend to use the type `()` here instead?
 note: required by a bound in `foo`
   --> $DIR/defaulted-never-note.rs:25:11
diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr b/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr
index ce5bbfc249e..72cd6938057 100644
--- a/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr
+++ b/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr
@@ -5,7 +5,7 @@ LL |     unconstrained_arg(return);
    |     ^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `!`
    |
    = note: this trait is implemented for `()`
-   = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information).
+   = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information)
    = help: did you intend to use the type `()` here instead?
 note: required by a bound in `unconstrained_arg`
   --> $DIR/diverging-fallback-no-leak.rs:12:25
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
index 5406d51c644..c94adfe4ab3 100644
--- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
@@ -30,7 +30,22 @@ LL |     let _ = |A | B: E| ();
    |                  |
    |                  E
    |
-   = note: an implementation of `std::ops::BitOr` might be missing for `E`
+note: an implementation of `BitOr<_>` might be missing for `E`
+  --> $DIR/or-patterns-syntactic-fail.rs:6:1
+   |
+LL | enum E { A, B }
+   | ^^^^^^ must implement `BitOr<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
+   |
+LL | / pub trait BitOr<Rhs = Self> {
+LL | |     /// The resulting type after applying the `|` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn bitor(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr
index c5a0448e798..92e86bf5d6c 100644
--- a/src/test/ui/span/issue-39018.stderr
+++ b/src/test/ui/span/issue-39018.stderr
@@ -20,7 +20,22 @@ LL |     let y = World::Hello + World::Goodbye;
    |             |
    |             World
    |
-   = note: an implementation of `std::ops::Add` might be missing for `World`
+note: an implementation of `Add<_>` might be missing for `World`
+  --> $DIR/issue-39018.rs:15:1
+   |
+LL | enum World {
+   | ^^^^^^^^^^ must implement `Add<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Add<Rhs = Self> {
+LL | |     /// The resulting type after applying the `+` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn add(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0369]: cannot add `String` to `&str`
   --> $DIR/issue-39018.rs:11:22
diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
index 16ffc661fe0..ce981bc0098 100644
--- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
+++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
@@ -22,6 +22,14 @@ LL |     println!("{}", MyStruct.foo_one());
    |
    = note: the following trait bounds were not satisfied:
            `MyStruct: Foo`
+note: the following trait must be implemented
+  --> $DIR/specialization-trait-not-implemented.rs:7:1
+   |
+LL | / trait Foo {
+LL | |     fn foo_one(&self) -> &'static str;
+LL | |     fn foo_two(&self) -> &'static str;
+LL | | }
+   | |_^
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Foo` defines an item `foo_one`, perhaps you need to implement it
   --> $DIR/specialization-trait-not-implemented.rs:7:1
diff --git a/src/test/ui/suggestions/invalid-bin-op.stderr b/src/test/ui/suggestions/invalid-bin-op.stderr
index 7668eddf607..d18c24e53d0 100644
--- a/src/test/ui/suggestions/invalid-bin-op.stderr
+++ b/src/test/ui/suggestions/invalid-bin-op.stderr
@@ -6,7 +6,16 @@ LL |     let _ = s == t;
    |             |
    |             S<T>
    |
+note: an implementation of `PartialEq<_>` might be missing for `S<T>`
+  --> $DIR/invalid-bin-op.rs:5:1
+   |
+LL | struct S<T>(T);
+   | ^^^^^^^^^^^^^^^ must implement `PartialEq<_>`
    = note: the trait `std::cmp::PartialEq` is not implemented for `S<T>`
+help: consider annotating `S<T>` with `#[derive(PartialEq)]`
+   |
+LL | #[derive(PartialEq)]
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type/type-ascription-precedence.stderr b/src/test/ui/type/type-ascription-precedence.stderr
index 92d3f18e82f..ebce257b278 100644
--- a/src/test/ui/type/type-ascription-precedence.stderr
+++ b/src/test/ui/type/type-ascription-precedence.stderr
@@ -28,7 +28,22 @@ error[E0600]: cannot apply unary operator `-` to type `Z`
 LL |     -(S: Z);
    |     ^^^^^^^ cannot apply unary operator `-`
    |
-   = note: an implementation of `std::ops::Neg` might be missing for `Z`
+note: an implementation of `std::ops::Neg` might be missing for `Z`
+  --> $DIR/type-ascription-precedence.rs:9:1
+   |
+LL | struct Z;
+   | ^^^^^^^^^ must implement `std::ops::Neg`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Neg {
+LL | |     /// The resulting type after applying the `-` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn neg(self) -> Self::Output;
+LL | | }
+   | |_^
 
 error[E0308]: mismatched types
   --> $DIR/type-ascription-precedence.rs:45:5