about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-05-04 06:32:49 +0000
committerbors <bors@rust-lang.org>2020-05-04 06:32:49 +0000
commitd6823ba1666fa5f65e5fdd17cfc78ff227c092f2 (patch)
treeff83906186e0ccc897fc117fd332296249a83e65
parentff4df04799c406c8149a041c3163321758aac924 (diff)
parentb368229d9bbaa840e777d33e36e649967e7ecb04 (diff)
downloadrust-d6823ba1666fa5f65e5fdd17cfc78ff227c092f2.tar.gz
rust-d6823ba1666fa5f65e5fdd17cfc78ff227c092f2.zip
Auto merge of #71108 - estebank:suggest-proj-type-mismatch-constraint, r=oli-obk
On type mismatch involving associated type, suggest constraint

When an associated type is found when a specific type was expected, if
possible provide a structured suggestion constraining the associated
type in a bound.

```
error[E0271]: type mismatch resolving `<T as Foo>::Y == i32`
  --> $DIR/associated-types-multiple-types-one-trait.rs:13:5
   |
LL |     want_y(t);
   |     ^^^^^^ expected `i32`, found associated type
...
LL | fn want_y<T:Foo<Y=i32>>(t: &T) { }
   |                 ----- required by this bound in `want_y`
   |
   = note:         expected type `i32`
           found associated type `<T as Foo>::Y`
help: consider constraining the associated type `<T as Foo>::Y` to `i32`
   |
LL | fn have_x_want_y<T:Foo<X=u32, Y = i32>>(t: &T)
   |                             ^^^^^^^^^
```

```
error[E0308]: mismatched types
  --> $DIR/trait-with-missing-associated-type-restriction.rs:12:9
   |
LL |     qux(x.func())
   |         ^^^^^^^^ expected `usize`, found associated type
   |
   = note:         expected type `usize`
           found associated type `<impl Trait as Trait>::A`
help: consider constraining the associated type `<impl Trait as Trait>::A` to `usize`
   |
LL | fn foo(x: impl Trait<A = usize>) {
   |                     ^^^^^^^^^^
```

Fix #71035. Related to #70908.
-rw-r--r--src/librustc_infer/infer/error_reporting/mod.rs5
-rw-r--r--src/librustc_middle/traits/mod.rs3
-rw-r--r--src/librustc_middle/traits/structural_impls.rs1
-rw-r--r--src/librustc_middle/ty/error.rs429
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/suggestions.rs7
-rw-r--r--src/librustc_typeck/check/compare_method.rs1
-rw-r--r--src/test/ui/associated-const/associated-const-generic-obligations.stderr2
-rw-r--r--src/test/ui/associated-types/associated-types-eq-3.stderr6
-rw-r--r--src/test/ui/associated-types/associated-types-issue-20346.stderr2
-rw-r--r--src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr12
-rw-r--r--src/test/ui/associated-types/defaults-in-other-trait-items.rs8
-rw-r--r--src/test/ui/associated-types/defaults-in-other-trait-items.stderr12
-rw-r--r--src/test/ui/associated-types/defaults-specialization.stderr47
-rw-r--r--src/test/ui/associated-types/impl-trait-return-missing-constraint.rs32
-rw-r--r--src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr20
-rw-r--r--src/test/ui/associated-types/issue-26681.stderr2
-rw-r--r--src/test/ui/generic-associated-types/iterable.stderr8
-rw-r--r--src/test/ui/hrtb/issue-62203-hrtb-ice.stderr2
-rw-r--r--src/test/ui/impl-trait/bound-normalization-fail.stderr12
-rw-r--r--src/test/ui/impl-trait/equality2.stderr2
-rw-r--r--src/test/ui/impl-trait/universal-mismatched-type.stderr2
-rw-r--r--src/test/ui/issues/issue-13853.stderr2
-rw-r--r--src/test/ui/issues/issue-20225.stderr6
-rw-r--r--src/test/ui/issues/issue-32323.stderr6
-rw-r--r--src/test/ui/issues/issue-69306.stderr12
-rw-r--r--src/test/ui/mismatched_types/issue-35030.stderr2
-rw-r--r--src/test/ui/specialization/specialization-default-projection.stderr4
-rw-r--r--src/test/ui/specialization/specialization-default-types.stderr6
-rw-r--r--src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr4
-rw-r--r--src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.fixed43
-rw-r--r--src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.rs43
-rw-r--r--src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.stderr94
-rw-r--r--src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs43
-rw-r--r--src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr103
-rw-r--r--src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr12
35 files changed, 859 insertions, 136 deletions
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index 50e97c8fb7a..a8d6c01785f 100644
--- a/src/librustc_infer/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -1388,6 +1388,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         terr: &TypeError<'tcx>,
     ) {
         let span = cause.span(self.tcx);
+        debug!("note_type_err cause={:?} values={:?}, terr={:?}", cause, values, terr);
 
         // For some types of errors, expected-found does not make
         // sense, so just ignore the values we were given.
@@ -1599,11 +1600,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 self.tcx.hir().body_owner_def_id(hir::BodyId { hir_id: cause.body_id })
             });
         self.check_and_note_conflicting_crates(diag, terr);
-        self.tcx.note_and_explain_type_err(diag, terr, span, body_owner_def_id.to_def_id());
+        self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id());
 
         // It reads better to have the error origin as the final
         // thing.
-        self.note_error_origin(diag, &cause, exp_found);
+        self.note_error_origin(diag, cause, exp_found);
     }
 
     /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs
index d6989fd8e4e..3a05d577bfa 100644
--- a/src/librustc_middle/traits/mod.rs
+++ b/src/librustc_middle/traits/mod.rs
@@ -194,6 +194,9 @@ pub enum ObligationCauseCode<'tcx> {
     DerivedObligation(DerivedObligationCause<'tcx>),
 
     /// Error derived when matching traits/impls; see ObligationCause for more details
+    CompareImplConstObligation,
+
+    /// Error derived when matching traits/impls; see ObligationCause for more details
     CompareImplMethodObligation {
         item_name: ast::Name,
         impl_item_def_id: DefId,
diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs
index 69a5213d3e4..668c84ad5e6 100644
--- a/src/librustc_middle/traits/structural_impls.rs
+++ b/src/librustc_middle/traits/structural_impls.rs
@@ -164,6 +164,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
                 tcx.lift(cause).map(super::ImplDerivedObligation)
             }
             super::DerivedObligation(ref cause) => tcx.lift(cause).map(super::DerivedObligation),
+            super::CompareImplConstObligation => Some(super::CompareImplConstObligation),
             super::CompareImplMethodObligation {
                 item_name,
                 impl_item_def_id,
diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs
index 78a94b62d47..4e1a8b0e92f 100644
--- a/src/librustc_middle/ty/error.rs
+++ b/src/librustc_middle/ty/error.rs
@@ -1,10 +1,12 @@
+use crate::traits::{ObligationCause, ObligationCauseCode};
 use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt};
 use rustc_ast::ast;
-use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
+use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
+use rustc_errors::{pluralize, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_span::symbol::sym;
-use rustc_span::Span;
+use rustc_span::symbol::{sym, Symbol};
+use rustc_span::{BytePos, MultiSpan, Span};
 use rustc_target::spec::abi;
 
 use std::borrow::Cow;
@@ -332,11 +334,12 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         db: &mut DiagnosticBuilder<'_>,
         err: &TypeError<'tcx>,
+        cause: &ObligationCause<'tcx>,
         sp: Span,
         body_owner_def_id: DefId,
     ) {
         use self::TypeError::*;
-
+        debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
         match err {
             Sorts(values) => {
                 let expected_str = values.expected.sort_string(self);
@@ -370,7 +373,7 @@ impl<'tcx> TyCtxt<'tcx> {
                                     sp,
                                     "use a float literal",
                                     format!("{}.0", snippet),
-                                    Applicability::MachineApplicable,
+                                    MachineApplicable,
                                 );
                             }
                         }
@@ -401,7 +404,8 @@ impl<'tcx> TyCtxt<'tcx> {
                     (ty::Param(_), ty::Projection(_)) | (ty::Projection(_), ty::Param(_)) => {
                         db.note("you might be missing a type parameter or trait bound");
                     }
-                    (ty::Param(p), _) | (_, ty::Param(p)) => {
+                    (ty::Param(p), ty::Dynamic(..) | ty::Opaque(..))
+                    | (ty::Dynamic(..) | ty::Opaque(..), ty::Param(p)) => {
                         let generics = self.generics_of(body_owner_def_id);
                         let p_span = self.def_span(generics.type_param(p, self).def_id);
                         if !sp.contains(p_span) {
@@ -441,44 +445,40 @@ impl<T> Trait<T> for X {
                                  #traits-as-parameters",
                         );
                     }
-                    (ty::Projection(_), _) => {
-                        db.note(&format!(
-                            "consider constraining the associated type `{}` to `{}` or calling a \
-                             method that returns `{}`",
-                            values.expected, values.found, values.expected,
-                        ));
-                        if self.sess.teach(&db.get_code().unwrap()) {
-                            db.help(
-                                "given an associated type `T` and a method `foo`:
-```
-trait Trait {
-    type T;
-    fn foo(&self) -> Self::T;
-}
-```
-the only way of implementing method `foo` is to constrain `T` with an explicit associated type:
-```
-impl Trait for X {
-    type T = String;
-    fn foo(&self) -> Self::T { String::new() }
-}
-```",
-                            );
+                    (ty::Param(p), _) | (_, ty::Param(p)) => {
+                        let generics = self.generics_of(body_owner_def_id);
+                        let p_span = self.def_span(generics.type_param(p, self).def_id);
+                        if !sp.contains(p_span) {
+                            db.span_label(p_span, "this type parameter");
                         }
-                        db.note(
-                            "for more information, visit \
-                                 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
+                    }
+                    (ty::Projection(proj_ty), _) => {
+                        self.expected_projection(
+                            db,
+                            proj_ty,
+                            values,
+                            body_owner_def_id,
+                            &cause.code,
                         );
                     }
-                    (_, ty::Projection(_)) => {
-                        db.note(&format!(
+                    (_, ty::Projection(proj_ty)) => {
+                        let msg = format!(
                             "consider constraining the associated type `{}` to `{}`",
                             values.found, values.expected,
-                        ));
-                        db.note(
-                            "for more information, visit \
-                                 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
                         );
+                        if !self.suggest_constraint(
+                            db,
+                            &msg,
+                            body_owner_def_id,
+                            proj_ty,
+                            values.expected,
+                        ) {
+                            db.help(&msg);
+                            db.note(
+                                "for more information, visit \
+                                https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
+                            );
+                        }
                     }
                     _ => {}
                 }
@@ -513,4 +513,357 @@ impl Trait for X {
             _ => {}
         }
     }
+
+    fn suggest_constraint(
+        &self,
+        db: &mut DiagnosticBuilder<'_>,
+        msg: &str,
+        body_owner_def_id: DefId,
+        proj_ty: &ty::ProjectionTy<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        let assoc = self.associated_item(proj_ty.item_def_id);
+        let trait_ref = proj_ty.trait_ref(*self);
+        if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
+            if let Some(hir_generics) = item.generics() {
+                // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
+                // This will also work for `impl Trait`.
+                let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind {
+                    let generics = self.generics_of(body_owner_def_id);
+                    generics.type_param(&param_ty, *self).def_id
+                } else {
+                    return false;
+                };
+
+                // First look in the `where` clause, as this might be
+                // `fn foo<T>(x: T) where T: Trait`.
+                for predicate in hir_generics.where_clause.predicates {
+                    if let hir::WherePredicate::BoundPredicate(pred) = predicate {
+                        if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) =
+                            pred.bounded_ty.kind
+                        {
+                            if path.res.opt_def_id() == Some(def_id) {
+                                // This predicate is binding type param `A` in `<A as T>::Foo` to
+                                // something, potentially `T`.
+                            } else {
+                                continue;
+                            }
+                        } else {
+                            continue;
+                        }
+
+                        if self.constrain_generic_bound_associated_type_structured_suggestion(
+                            db,
+                            &trait_ref,
+                            pred.bounds,
+                            &assoc,
+                            ty,
+                            msg,
+                        ) {
+                            return true;
+                        }
+                    }
+                }
+                for param in hir_generics.params {
+                    if self.hir().opt_local_def_id(param.hir_id).map(|id| id.to_def_id())
+                        == Some(def_id)
+                    {
+                        // This is type param `A` in `<A as T>::Foo`.
+                        return self.constrain_generic_bound_associated_type_structured_suggestion(
+                            db,
+                            &trait_ref,
+                            param.bounds,
+                            &assoc,
+                            ty,
+                            msg,
+                        );
+                    }
+                }
+            }
+        }
+        false
+    }
+
+    /// An associated type was expected and a different type was found.
+    ///
+    /// We perform a few different checks to see what we can suggest:
+    ///
+    ///  - In the current item, look for associated functions that return the expected type and
+    ///    suggest calling them. (Not a structured suggestion.)
+    ///  - If any of the item's generic bounds can be constrained, we suggest constraining the
+    ///    associated type to the found type.
+    ///  - If the associated type has a default type and was expected inside of a `trait`, we
+    ///    mention that this is disallowed.
+    ///  - If all other things fail, and the error is not because of a mismatch between the `trait`
+    ///    and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc
+    ///    fn that returns the type.
+    fn expected_projection(
+        &self,
+        db: &mut DiagnosticBuilder<'_>,
+        proj_ty: &ty::ProjectionTy<'tcx>,
+        values: &ExpectedFound<Ty<'tcx>>,
+        body_owner_def_id: DefId,
+        cause_code: &ObligationCauseCode<'_>,
+    ) {
+        let msg = format!(
+            "consider constraining the associated type `{}` to `{}`",
+            values.expected, values.found
+        );
+        let body_owner = self.hir().get_if_local(body_owner_def_id);
+        let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
+
+        // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
+        let callable_scope = match body_owner {
+            Some(
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
+                | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
+                | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
+            ) => true,
+            _ => false,
+        };
+        let impl_comparison = matches!(
+            cause_code,
+            ObligationCauseCode::CompareImplMethodObligation { .. }
+                | ObligationCauseCode::CompareImplTypeObligation { .. }
+                | ObligationCauseCode::CompareImplConstObligation
+        );
+        let assoc = self.associated_item(proj_ty.item_def_id);
+        if !callable_scope || impl_comparison {
+            // We do not want to suggest calling functions when the reason of the
+            // type error is a comparison of an `impl` with its `trait` or when the
+            // scope is outside of a `Body`.
+        } else {
+            // If we find a suitable associated function that returns the expected type, we don't
+            // want the more general suggestion later in this method about "consider constraining
+            // the associated type or calling a method that returns the associated type".
+            let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
+                db,
+                assoc.container.id(),
+                current_method_ident,
+                proj_ty.item_def_id,
+                values.expected,
+            );
+            // Possibly suggest constraining the associated type to conform to the
+            // found type.
+            if self.suggest_constraint(db, &msg, body_owner_def_id, proj_ty, values.found)
+                || point_at_assoc_fn
+            {
+                return;
+            }
+        }
+
+        if let ty::Opaque(def_id, _) = proj_ty.self_ty().kind {
+            // When the expected `impl Trait` is not defined in the current item, it will come from
+            // a return type. This can occur when dealing with `TryStream` (#71035).
+            if self.constrain_associated_type_structured_suggestion(
+                db,
+                self.def_span(def_id),
+                &assoc,
+                values.found,
+                &msg,
+            ) {
+                return;
+            }
+        }
+
+        if self.point_at_associated_type(db, body_owner_def_id, values.found) {
+            return;
+        }
+
+        if !impl_comparison {
+            // Generic suggestion when we can't be more specific.
+            if callable_scope {
+                db.help(&format!("{} or calling a method that returns `{}`", msg, values.expected));
+            } else {
+                db.help(&msg);
+            }
+            db.note(
+                "for more information, visit \
+                 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
+            );
+        }
+        if self.sess.teach(&db.get_code().unwrap()) {
+            db.help(
+                "given an associated type `T` and a method `foo`:
+```
+trait Trait {
+type T;
+fn foo(&self) -> Self::T;
+}
+```
+the only way of implementing method `foo` is to constrain `T` with an explicit associated type:
+```
+impl Trait for X {
+type T = String;
+fn foo(&self) -> Self::T { String::new() }
+}
+```",
+            );
+        }
+    }
+
+    fn point_at_methods_that_satisfy_associated_type(
+        &self,
+        db: &mut DiagnosticBuilder<'_>,
+        assoc_container_id: DefId,
+        current_method_ident: Option<Symbol>,
+        proj_ty_item_def_id: DefId,
+        expected: Ty<'tcx>,
+    ) -> bool {
+        let items = self.associated_items(assoc_container_id);
+        // Find all the methods in the trait that could be called to construct the
+        // expected associated type.
+        // FIXME: consider suggesting the use of associated `const`s.
+        let methods: Vec<(Span, String)> = items
+            .items
+            .iter()
+            .filter(|(name, item)| {
+                ty::AssocKind::Fn == item.kind && Some(**name) != current_method_ident
+            })
+            .filter_map(|(_, item)| {
+                let method = self.fn_sig(item.def_id);
+                match method.output().skip_binder().kind {
+                    ty::Projection(ty::ProjectionTy { item_def_id, .. })
+                        if item_def_id == proj_ty_item_def_id =>
+                    {
+                        Some((
+                            self.sess.source_map().guess_head_span(self.def_span(item.def_id)),
+                            format!("consider calling `{}`", self.def_path_str(item.def_id)),
+                        ))
+                    }
+                    _ => None,
+                }
+            })
+            .collect();
+        if !methods.is_empty() {
+            // Use a single `help:` to show all the methods in the trait that can
+            // be used to construct the expected associated type.
+            let mut span: MultiSpan =
+                methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
+            let msg = format!(
+                "{some} method{s} {are} available that return{r} `{ty}`",
+                some = if methods.len() == 1 { "a" } else { "some" },
+                s = pluralize!(methods.len()),
+                are = if methods.len() == 1 { "is" } else { "are" },
+                r = if methods.len() == 1 { "s" } else { "" },
+                ty = expected
+            );
+            for (sp, label) in methods.into_iter() {
+                span.push_span_label(sp, label);
+            }
+            db.span_help(span, &msg);
+            return true;
+        }
+        false
+    }
+
+    fn point_at_associated_type(
+        &self,
+        db: &mut DiagnosticBuilder<'_>,
+        body_owner_def_id: DefId,
+        found: Ty<'tcx>,
+    ) -> bool {
+        let hir_id = match body_owner_def_id.as_local().map(|id| self.hir().as_local_hir_id(id)) {
+            Some(hir_id) => hir_id,
+            None => return false,
+        };
+        // When `body_owner` is an `impl` or `trait` item, look in its associated types for
+        // `expected` and point at it.
+        let parent_id = self.hir().get_parent_item(hir_id);
+        let item = self.hir().find(parent_id);
+        debug!("expected_projection parent item {:?}", item);
+        match item {
+            Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
+                // FIXME: account for `#![feature(specialization)]`
+                for item in &items[..] {
+                    match item.kind {
+                        hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => {
+                            if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found {
+                                if let hir::Defaultness::Default { has_value: true } =
+                                    item.defaultness
+                                {
+                                    db.span_label(
+                                        item.span,
+                                        "associated type defaults can't be assumed inside the \
+                                            trait defining them",
+                                    );
+                                } else {
+                                    db.span_label(item.span, "expected this associated type");
+                                }
+                                return true;
+                            }
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Impl { items, .. }, ..
+            })) => {
+                for item in &items[..] {
+                    match item.kind {
+                        hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => {
+                            if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found {
+                                db.span_label(item.span, "expected this associated type");
+                                return true;
+                            }
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            _ => {}
+        }
+        false
+    }
+
+    /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
+    /// requirement, provide a strucuted suggestion to constrain it to a given type `ty`.
+    fn constrain_generic_bound_associated_type_structured_suggestion(
+        &self,
+        db: &mut DiagnosticBuilder<'_>,
+        trait_ref: &ty::TraitRef<'tcx>,
+        bounds: hir::GenericBounds<'_>,
+        assoc: &ty::AssocItem,
+        ty: Ty<'tcx>,
+        msg: &str,
+    ) -> bool {
+        // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
+        bounds.iter().any(|bound| match bound {
+            hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => {
+                // Relate the type param against `T` in `<A as T>::Foo`.
+                ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
+                    && self.constrain_associated_type_structured_suggestion(
+                        db, ptr.span, assoc, ty, msg,
+                    )
+            }
+            _ => false,
+        })
+    }
+
+    /// Given a span corresponding to a bound, provide a structured suggestion to set an
+    /// associated type to a given type `ty`.
+    fn constrain_associated_type_structured_suggestion(
+        &self,
+        db: &mut DiagnosticBuilder<'_>,
+        span: Span,
+        assoc: &ty::AssocItem,
+        ty: Ty<'tcx>,
+        msg: &str,
+    ) -> bool {
+        if let Ok(has_params) =
+            self.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>'))
+        {
+            let (span, sugg) = if has_params {
+                let pos = span.hi() - BytePos(1);
+                let span = Span::new(pos, pos, span.ctxt());
+                (span, format!(", {} = {}", assoc.ident, ty))
+            } else {
+                (span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
+            };
+            db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
+            return true;
+        }
+        false
+    }
 }
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index 5ec2d68ab2a..ce7b1390d46 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -1738,6 +1738,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     predicate
                 ));
             }
+            ObligationCauseCode::CompareImplConstObligation => {
+                err.note(&format!(
+                    "the requirement `{}` appears on the associated impl constant \
+                     but not on the corresponding associated trait constant",
+                    predicate
+                ));
+            }
             ObligationCauseCode::ReturnType
             | ObligationCauseCode::ReturnValue(_)
             | ObligationCauseCode::BlockTailExpression(_) => (),
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 6e4af6d769a..29cd9681295 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -966,6 +966,7 @@ crate fn compare_const_impl<'tcx>(
         let impl_ty = tcx.type_of(impl_c.def_id);
         let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
         let mut cause = ObligationCause::misc(impl_c_span, impl_c_hir_id);
+        cause.code = ObligationCauseCode::CompareImplConstObligation;
 
         // There is no "body" here, so just pass dummy id.
         let impl_ty =
diff --git a/src/test/ui/associated-const/associated-const-generic-obligations.stderr b/src/test/ui/associated-const/associated-const-generic-obligations.stderr
index d6cdcd4747f..d8bac07e058 100644
--- a/src/test/ui/associated-const/associated-const-generic-obligations.stderr
+++ b/src/test/ui/associated-const/associated-const-generic-obligations.stderr
@@ -9,8 +9,6 @@ LL |     const FROM: &'static str = "foo";
    |
    = note: expected associated type `<T as Foo>::Out`
                     found reference `&'static str`
-   = note: consider constraining the associated type `<T as Foo>::Out` to `&'static str` or calling a method that returns `<T as Foo>::Out`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-eq-3.stderr b/src/test/ui/associated-types/associated-types-eq-3.stderr
index a8608abb4d9..dffa4780a09 100644
--- a/src/test/ui/associated-types/associated-types-eq-3.stderr
+++ b/src/test/ui/associated-types/associated-types-eq-3.stderr
@@ -8,8 +8,10 @@ LL |     let _: Bar = x.boo();
    |
    = note:       expected struct `Bar`
            found associated type `<I as Foo>::A`
-   = note: consider constraining the associated type `<I as Foo>::A` to `Bar`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+help: consider constraining the associated type `<I as Foo>::A` to `Bar`
+   |
+LL | fn foo2<I: Foo<A = Bar>>(x: I) {
+   |               ^^^^^^^^^
 
 error[E0271]: type mismatch resolving `<isize as Foo>::A == Bar`
   --> $DIR/associated-types-eq-3.rs:38:5
diff --git a/src/test/ui/associated-types/associated-types-issue-20346.stderr b/src/test/ui/associated-types/associated-types-issue-20346.stderr
index 8f2b760840c..db35c1af171 100644
--- a/src/test/ui/associated-types/associated-types-issue-20346.stderr
+++ b/src/test/ui/associated-types/associated-types-issue-20346.stderr
@@ -12,8 +12,6 @@ LL |     is_iterator_of::<Option<T>, _>(&adapter);
    |
    = note: expected enum `std::option::Option<T>`
               found type `T`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr b/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr
index 4e481411b4d..b8f20d00ff8 100644
--- a/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr
+++ b/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr
@@ -9,8 +9,10 @@ LL | fn want_y<T:Foo<Y=i32>>(t: &T) { }
    |
    = note:         expected type `i32`
            found associated type `<T as Foo>::Y`
-   = note: consider constraining the associated type `<T as Foo>::Y` to `i32`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+help: consider constraining the associated type `<T as Foo>::Y` to `i32`
+   |
+LL | fn have_x_want_y<T:Foo<X=u32, Y = i32>>(t: &T)
+   |                             ^^^^^^^^^
 
 error[E0271]: type mismatch resolving `<T as Foo>::X == u32`
   --> $DIR/associated-types-multiple-types-one-trait.rs:18:5
@@ -23,8 +25,10 @@ LL | fn want_x<T:Foo<X=u32>>(t: &T) { }
    |
    = note:         expected type `u32`
            found associated type `<T as Foo>::X`
-   = note: consider constraining the associated type `<T as Foo>::X` to `u32`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+help: consider constraining the associated type `<T as Foo>::X` to `u32`
+   |
+LL | fn have_y_want_x<T:Foo<Y=i32, X = u32>>(t: &T)
+   |                             ^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items.rs b/src/test/ui/associated-types/defaults-in-other-trait-items.rs
index 9f2e8aca477..4014f46285d 100644
--- a/src/test/ui/associated-types/defaults-in-other-trait-items.rs
+++ b/src/test/ui/associated-types/defaults-in-other-trait-items.rs
@@ -3,15 +3,13 @@
 // Associated type defaults may not be assumed inside the trait defining them.
 // ie. they only resolve to `<Self as Tr>::A`, not the actual type `()`
 trait Tr {
-    type A = ();
+    type A = (); //~ NOTE associated type defaults can't be assumed inside the trait defining them
 
     fn f(p: Self::A) {
         let () = p;
         //~^ ERROR mismatched types
         //~| NOTE expected associated type, found `()`
         //~| NOTE expected associated type `<Self as Tr>::A`
-        //~| NOTE consider constraining the associated type
-        //~| NOTE for more information, visit
     }
 }
 
@@ -31,15 +29,13 @@ impl Tr for u8 {
 }
 
 trait AssocConst {
-    type Ty = u8;
+    type Ty = u8; //~ NOTE associated type defaults can't be assumed inside the trait defining them
 
     // Assoc. consts also cannot assume that default types hold
     const C: Self::Ty = 0u8;
     //~^ ERROR mismatched types
     //~| NOTE expected associated type, found `u8`
     //~| NOTE expected associated type `<Self as AssocConst>::Ty`
-    //~| NOTE consider constraining the associated type
-    //~| NOTE for more information, visit
 }
 
 // An impl can, however
diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items.stderr b/src/test/ui/associated-types/defaults-in-other-trait-items.stderr
index 9ecfe49c2b5..493df30a64d 100644
--- a/src/test/ui/associated-types/defaults-in-other-trait-items.stderr
+++ b/src/test/ui/associated-types/defaults-in-other-trait-items.stderr
@@ -1,24 +1,26 @@
 error[E0308]: mismatched types
   --> $DIR/defaults-in-other-trait-items.rs:9:13
    |
+LL |     type A = ();
+   |     ------------ associated type defaults can't be assumed inside the trait defining them
+...
 LL |         let () = p;
    |             ^^ expected associated type, found `()`
    |
    = note: expected associated type `<Self as Tr>::A`
                     found unit type `()`
-   = note: consider constraining the associated type `<Self as Tr>::A` to `()` or calling a method that returns `<Self as Tr>::A`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0308]: mismatched types
-  --> $DIR/defaults-in-other-trait-items.rs:37:25
+  --> $DIR/defaults-in-other-trait-items.rs:35:25
    |
+LL |     type Ty = u8;
+   |     ------------- associated type defaults can't be assumed inside the trait defining them
+...
 LL |     const C: Self::Ty = 0u8;
    |                         ^^^ expected associated type, found `u8`
    |
    = note: expected associated type `<Self as AssocConst>::Ty`
                          found type `u8`
-   = note: consider constraining the associated type `<Self as AssocConst>::Ty` to `u8` or calling a method that returns `<Self as AssocConst>::Ty`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr
index 1dd536ec636..37a4d9b60fd 100644
--- a/src/test/ui/associated-types/defaults-specialization.stderr
+++ b/src/test/ui/associated-types/defaults-specialization.stderr
@@ -9,8 +9,6 @@ LL |     fn make() -> u8 { 0 }
    |
    = note: expected fn pointer `fn() -> <A<T> as Tr>::Ty`
               found fn pointer `fn() -> u8`
-   = note: consider constraining the associated type `<A<T> as Tr>::Ty` to `u8` or calling a method that returns `<A<T> as Tr>::Ty`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0053]: method `make` has an incompatible type for trait
   --> $DIR/defaults-specialization.rs:34:18
@@ -18,17 +16,21 @@ error[E0053]: method `make` has an incompatible type for trait
 LL |     fn make() -> Self::Ty {
    |                  -------- type in trait
 ...
+LL |     default type Ty = bool;
+   |     ----------------------- expected this associated type
+LL | 
 LL |     fn make() -> bool { true }
    |                  ^^^^ expected associated type, found `bool`
    |
    = note: expected fn pointer `fn() -> <B<T> as Tr>::Ty`
               found fn pointer `fn() -> bool`
-   = note: consider constraining the associated type `<B<T> as Tr>::Ty` to `bool` or calling a method that returns `<B<T> as Tr>::Ty`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0308]: mismatched types
   --> $DIR/defaults-specialization.rs:9:9
    |
+LL |     type Ty = u8;
+   |     ------------- associated type defaults can't be assumed inside the trait defining them
+LL | 
 LL |     fn make() -> Self::Ty {
    |                  -------- expected `<Self as Tr>::Ty` because of return type
 LL |         0u8
@@ -36,8 +38,6 @@ LL |         0u8
    |
    = note: expected associated type `<Self as Tr>::Ty`
                          found type `u8`
-   = note: consider constraining the associated type `<Self as Tr>::Ty` to `u8` or calling a method that returns `<Self as Tr>::Ty`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0308]: mismatched types
   --> $DIR/defaults-specialization.rs:25:29
@@ -49,12 +49,15 @@ LL |     fn make() -> Self::Ty { 0u8 }
    |
    = note: expected associated type `<A2<T> as Tr>::Ty`
                          found type `u8`
-   = note: consider constraining the associated type `<A2<T> as Tr>::Ty` to `u8` or calling a method that returns `<A2<T> as Tr>::Ty`
+   = help: consider constraining the associated type `<A2<T> as Tr>::Ty` to `u8` or calling a method that returns `<A2<T> as Tr>::Ty`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0308]: mismatched types
   --> $DIR/defaults-specialization.rs:43:29
    |
+LL |     default type Ty = bool;
+   |     ----------------------- expected this associated type
+LL | 
 LL |     fn make() -> Self::Ty { true }
    |                  --------   ^^^^ expected associated type, found `bool`
    |                  |
@@ -62,8 +65,6 @@ LL |     fn make() -> Self::Ty { true }
    |
    = note: expected associated type `<B2<T> as Tr>::Ty`
                          found type `bool`
-   = note: consider constraining the associated type `<B2<T> as Tr>::Ty` to `bool` or calling a method that returns `<B2<T> as Tr>::Ty`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0308]: mismatched types
   --> $DIR/defaults-specialization.rs:86:32
@@ -75,8 +76,11 @@ LL |     let _: <B<()> as Tr>::Ty = 0u8;
    |
    = note: expected associated type `<B<()> as Tr>::Ty`
                          found type `u8`
-   = note: consider constraining the associated type `<B<()> as Tr>::Ty` to `u8` or calling a method that returns `<B<()> as Tr>::Ty`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+help: a method is available that returns `<B<()> as Tr>::Ty`
+  --> $DIR/defaults-specialization.rs:8:5
+   |
+LL |     fn make() -> Self::Ty {
+   |     ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
 
 error[E0308]: mismatched types
   --> $DIR/defaults-specialization.rs:87:32
@@ -88,8 +92,11 @@ LL |     let _: <B<()> as Tr>::Ty = true;
    |
    = note: expected associated type `<B<()> as Tr>::Ty`
                          found type `bool`
-   = note: consider constraining the associated type `<B<()> as Tr>::Ty` to `bool` or calling a method that returns `<B<()> as Tr>::Ty`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+help: a method is available that returns `<B<()> as Tr>::Ty`
+  --> $DIR/defaults-specialization.rs:8:5
+   |
+LL |     fn make() -> Self::Ty {
+   |     ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
 
 error[E0308]: mismatched types
   --> $DIR/defaults-specialization.rs:88:33
@@ -101,8 +108,11 @@ LL |     let _: <B2<()> as Tr>::Ty = 0u8;
    |
    = note: expected associated type `<B2<()> as Tr>::Ty`
                          found type `u8`
-   = note: consider constraining the associated type `<B2<()> as Tr>::Ty` to `u8` or calling a method that returns `<B2<()> as Tr>::Ty`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+help: a method is available that returns `<B2<()> as Tr>::Ty`
+  --> $DIR/defaults-specialization.rs:8:5
+   |
+LL |     fn make() -> Self::Ty {
+   |     ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
 
 error[E0308]: mismatched types
   --> $DIR/defaults-specialization.rs:89:33
@@ -114,8 +124,11 @@ LL |     let _: <B2<()> as Tr>::Ty = true;
    |
    = note: expected associated type `<B2<()> as Tr>::Ty`
                          found type `bool`
-   = note: consider constraining the associated type `<B2<()> as Tr>::Ty` to `bool` or calling a method that returns `<B2<()> as Tr>::Ty`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+help: a method is available that returns `<B2<()> as Tr>::Ty`
+  --> $DIR/defaults-specialization.rs:8:5
+   |
+LL |     fn make() -> Self::Ty {
+   |     ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/associated-types/impl-trait-return-missing-constraint.rs b/src/test/ui/associated-types/impl-trait-return-missing-constraint.rs
new file mode 100644
index 00000000000..5f994f26534
--- /dev/null
+++ b/src/test/ui/associated-types/impl-trait-return-missing-constraint.rs
@@ -0,0 +1,32 @@
+trait Foo {
+    type Item;
+}
+
+trait Bar: Foo {}
+
+struct S;
+
+impl Foo for S {
+    type Item = i32;
+}
+impl Bar for S {}
+
+struct T;
+
+impl Foo for T {
+    type Item = u32;
+}
+impl Bar for T {}
+
+fn bar() -> impl Bar {
+    T
+}
+
+fn baz() -> impl Bar<Item = i32> {
+//~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
+    bar()
+}
+
+fn main() {
+    let _ = baz();
+}
diff --git a/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr
new file mode 100644
index 00000000000..566e390a31e
--- /dev/null
+++ b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr
@@ -0,0 +1,20 @@
+error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
+  --> $DIR/impl-trait-return-missing-constraint.rs:25:13
+   |
+LL | fn bar() -> impl Bar {
+   |             -------- the expected opaque type
+...
+LL | fn baz() -> impl Bar<Item = i32> {
+   |             ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32`
+   |
+   = note: expected associated type `<impl Bar as Foo>::Item`
+                         found type `i32`
+   = note: the return type of a function must have a statically known size
+help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
+   |
+LL | fn bar() -> impl Bar<Item = i32> {
+   |                     ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/issue-26681.stderr b/src/test/ui/associated-types/issue-26681.stderr
index da10933df92..74411008c9d 100644
--- a/src/test/ui/associated-types/issue-26681.stderr
+++ b/src/test/ui/associated-types/issue-26681.stderr
@@ -6,7 +6,7 @@ LL |     const C: <Self::Fv as Foo>::Bar = 6665;
    |
    = note: expected associated type `<<Self as Baz>::Fv as Foo>::Bar`
                          found type `{integer}`
-   = note: consider constraining the associated type `<<Self as Baz>::Fv as Foo>::Bar` to `{integer}` or calling a method that returns `<<Self as Baz>::Fv as Foo>::Bar`
+   = help: consider constraining the associated type `<<Self as Baz>::Fv as Foo>::Bar` to `{integer}`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error: aborting due to previous error
diff --git a/src/test/ui/generic-associated-types/iterable.stderr b/src/test/ui/generic-associated-types/iterable.stderr
index b1298163aab..6e754621225 100644
--- a/src/test/ui/generic-associated-types/iterable.stderr
+++ b/src/test/ui/generic-associated-types/iterable.stderr
@@ -6,7 +6,7 @@ LL |     type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item
    |
    = note:    expected reference `&T`
            found associated type `<std::vec::Vec<T> as Iterable>::Item<'_>`
-   = note: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_`
+   = help: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>`
@@ -17,7 +17,7 @@ LL |     type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item
    |
    = note:    expected reference `&T`
            found associated type `<[T] as Iterable>::Item<'_>`
-   = note: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_`
+   = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0271]: type mismatch resolving `for<'a> <<std::vec::Vec<T> as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <std::vec::Vec<T> as Iterable>::Item<'a>`
@@ -34,7 +34,7 @@ LL |     fn iter<'a>(&'a self) -> Self::Iter<'a> {
    |
    = note: expected associated type `<std::vec::Vec<T> as Iterable>::Item<'_>`
                     found reference `&T`
-   = note: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_` or calling a method that returns `<std::vec::Vec<T> as Iterable>::Item<'_>`
+   = help: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_` or calling a method that returns `<std::vec::Vec<T> as Iterable>::Item<'_>`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>`
@@ -51,7 +51,7 @@ LL |     fn iter<'a>(&'a self) -> Self::Iter<'a> {
    |
    = note: expected associated type `<[T] as Iterable>::Item<'_>`
                     found reference `&T`
-   = note: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` or calling a method that returns `<[T] as Iterable>::Item<'_>`
+   = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` or calling a method that returns `<[T] as Iterable>::Item<'_>`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
index 759c7302d13..1c7bfa65d7c 100644
--- a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
+++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
@@ -6,7 +6,7 @@ LL |     let v = Unit2.m(
    |
    = note:       expected struct `Unit4`
            found associated type `<_ as Ty<'_>>::V`
-   = note: consider constraining the associated type `<_ as Ty<'_>>::V` to `Unit4`
+   = help: consider constraining the associated type `<_ as Ty<'_>>::V` to `Unit4`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0271]: type mismatch resolving `<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as std::ops::FnOnce<((&u8,),)>>::Output == Unit3`
diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr
index 314ed96fd5e..f5092044627 100644
--- a/src/test/ui/impl-trait/bound-normalization-fail.stderr
+++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr
@@ -14,9 +14,11 @@ LL |     fn foo_fail<T: Trait>() -> impl FooLike<Output=T::Assoc> {
    |
    = note:         expected type `()`
            found associated type `<T as impl_trait::Trait>::Assoc`
-   = note: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
    = note: the return type of a function must have a statically known size
+help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
+   |
+LL |     fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
+   |                         ^^^^^^^^^^^^
 
 error: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
   --> $DIR/bound-normalization-fail.rs:43:41
@@ -32,9 +34,11 @@ LL |     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
    |
    = note:         expected type `()`
            found associated type `<T as lifetimes::Trait<'static>>::Assoc`
-   = note: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
    = note: the return type of a function must have a statically known size
+help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
+   |
+LL |     fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
+   |                                 ^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr
index b882514f616..2454c218ffc 100644
--- a/src/test/ui/impl-trait/equality2.stderr
+++ b/src/test/ui/impl-trait/equality2.stderr
@@ -25,7 +25,7 @@ LL |     let _: i32 = Leak::leak(hide(0_i32));
    |
    = note:         expected type `i32`
            found associated type `<impl Foo as Leak>::T`
-   = note: consider constraining the associated type `<impl Foo as Leak>::T` to `i32`
+   = help: consider constraining the associated type `<impl Foo as Leak>::T` to `i32`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0308]: mismatched types
diff --git a/src/test/ui/impl-trait/universal-mismatched-type.stderr b/src/test/ui/impl-trait/universal-mismatched-type.stderr
index 3ffa2b55712..a12b01b4d2b 100644
--- a/src/test/ui/impl-trait/universal-mismatched-type.stderr
+++ b/src/test/ui/impl-trait/universal-mismatched-type.stderr
@@ -10,8 +10,6 @@ LL |     x
    |
    = note:      expected struct `std::string::String`
            found type parameter `impl Debug`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-13853.stderr b/src/test/ui/issues/issue-13853.stderr
index 2f31636f8ad..3f1b955dddb 100644
--- a/src/test/ui/issues/issue-13853.stderr
+++ b/src/test/ui/issues/issue-13853.stderr
@@ -9,8 +9,6 @@ LL |         self.iter()
    |
    = note: expected type parameter `I`
                       found struct `std::slice::Iter<'_, N>`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0599]: no method named `iter` found for reference `&G` in the current scope
   --> $DIR/issue-13853.rs:27:23
diff --git a/src/test/ui/issues/issue-20225.stderr b/src/test/ui/issues/issue-20225.stderr
index 1c5911e05f7..3bcc50ded84 100644
--- a/src/test/ui/issues/issue-20225.stderr
+++ b/src/test/ui/issues/issue-20225.stderr
@@ -8,8 +8,6 @@ LL |   extern "rust-call" fn call(&self, (_,): (T,)) {}
    |
    = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))`
               found fn pointer `extern "rust-call" fn(&Foo, (T,))`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0053]: method `call_mut` has an incompatible type for trait
   --> $DIR/issue-20225.rs:11:3
@@ -21,8 +19,6 @@ LL |   extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {}
    |
    = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))`
               found fn pointer `extern "rust-call" fn(&mut Foo, (T,))`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0053]: method `call_once` has an incompatible type for trait
   --> $DIR/issue-20225.rs:18:3
@@ -35,8 +31,6 @@ LL |   extern "rust-call" fn call_once(self, (_,): (T,)) {}
    |
    = note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))`
               found fn pointer `extern "rust-call" fn(Foo, (T,))`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/issues/issue-32323.stderr b/src/test/ui/issues/issue-32323.stderr
index 7c0928b1924..369f56b9869 100644
--- a/src/test/ui/issues/issue-32323.stderr
+++ b/src/test/ui/issues/issue-32323.stderr
@@ -8,8 +8,10 @@ LL | pub fn f<'a, T: Tr<'a>>() -> <T as Tr<'a>>::Out {}
    |
    = note: expected associated type `<T as Tr<'a>>::Out`
                     found unit type `()`
-   = note: consider constraining the associated type `<T as Tr<'a>>::Out` to `()` or calling a method that returns `<T as Tr<'a>>::Out`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+help: consider constraining the associated type `<T as Tr<'a>>::Out` to `()`
+   |
+LL | pub fn f<'a, T: Tr<'a, Out = ()>>() -> <T as Tr<'a>>::Out {}
+   |                      ^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-69306.stderr b/src/test/ui/issues/issue-69306.stderr
index a2a42739ca8..58e85ec700d 100644
--- a/src/test/ui/issues/issue-69306.stderr
+++ b/src/test/ui/issues/issue-69306.stderr
@@ -8,8 +8,6 @@ LL |     const C: S0<u8> = Self(0);
    |
    = note: expected type parameter `T`
                         found type `{integer}`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0308]: mismatched types
   --> $DIR/issue-69306.rs:5:23
@@ -21,8 +19,6 @@ LL |     const C: S0<u8> = Self(0);
    |
    = note: expected struct `S0<u8>`
               found struct `S0<T>`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0308]: mismatched types
   --> $DIR/issue-69306.rs:10:14
@@ -35,8 +31,6 @@ LL |         Self(0);
    |
    = note: expected type parameter `T`
                         found type `{integer}`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0308]: mismatched types
   --> $DIR/issue-69306.rs:27:14
@@ -49,8 +43,6 @@ LL |         Self(0);
    |
    = note: expected type parameter `T`
                         found type `{integer}`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0308]: mismatched types
   --> $DIR/issue-69306.rs:33:32
@@ -62,8 +54,6 @@ LL |     const C: S1<u8, u8> = Self(0, 1);
    |
    = note: expected type parameter `T`
                         found type `{integer}`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0308]: mismatched types
   --> $DIR/issue-69306.rs:33:27
@@ -75,8 +65,6 @@ LL |     const C: S1<u8, u8> = Self(0, 1);
    |
    = note: expected struct `S1<u8, _>`
               found struct `S1<T, _>`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0308]: mismatched types
   --> $DIR/issue-69306.rs:41:14
diff --git a/src/test/ui/mismatched_types/issue-35030.stderr b/src/test/ui/mismatched_types/issue-35030.stderr
index 6fb04ef5c99..9f4e4398984 100644
--- a/src/test/ui/mismatched_types/issue-35030.stderr
+++ b/src/test/ui/mismatched_types/issue-35030.stderr
@@ -9,8 +9,6 @@ LL |         Some(true)
    |
    = note: expected type parameter `bool` (type parameter `bool`)
                         found type `bool` (`bool`)
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/specialization/specialization-default-projection.stderr b/src/test/ui/specialization/specialization-default-projection.stderr
index d03aec7ab30..ac15ab0681a 100644
--- a/src/test/ui/specialization/specialization-default-projection.stderr
+++ b/src/test/ui/specialization/specialization-default-projection.stderr
@@ -9,7 +9,7 @@ LL |     ()
    |
    = note: expected associated type `<T as Foo>::Assoc`
                     found unit type `()`
-   = note: consider constraining the associated type `<T as Foo>::Assoc` to `()` or calling a method that returns `<T as Foo>::Assoc`
+   = help: consider constraining the associated type `<T as Foo>::Assoc` to `()` or calling a method that returns `<T as Foo>::Assoc`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0308]: mismatched types
@@ -25,7 +25,7 @@ LL |     generic::<()>()
    |
    = note:    expected unit type `()`
            found associated type `<() as Foo>::Assoc`
-   = note: consider constraining the associated type `<() as Foo>::Assoc` to `()`
+   = help: consider constraining the associated type `<() as Foo>::Assoc` to `()`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr
index 257c114252c..7233387eba1 100644
--- a/src/test/ui/specialization/specialization-default-types.stderr
+++ b/src/test/ui/specialization/specialization-default-types.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/specialization-default-types.rs:15:9
    |
+LL |     default type Output = Box<T>;
+   |     ----------------------------- expected this associated type
 LL |     default fn generate(self) -> Self::Output {
    |                                  ------------ expected `<T as Example>::Output` because of return type
 LL |         Box::new(self)
@@ -8,8 +10,6 @@ LL |         Box::new(self)
    |
    = note: expected associated type `<T as Example>::Output`
                        found struct `std::boxed::Box<T>`
-   = note: consider constraining the associated type `<T as Example>::Output` to `std::boxed::Box<T>` or calling a method that returns `<T as Example>::Output`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0308]: mismatched types
   --> $DIR/specialization-default-types.rs:25:5
@@ -21,7 +21,7 @@ LL |     Example::generate(t)
    |
    = note:       expected struct `std::boxed::Box<T>`
            found associated type `<T as Example>::Output`
-   = note: consider constraining the associated type `<T as Example>::Output` to `std::boxed::Box<T>`
+   = help: consider constraining the associated type `<T as Example>::Output` to `std::boxed::Box<T>`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
index ff256eb3094..52e13dbc2dd 100644
--- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
+++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
@@ -12,8 +12,6 @@ LL |     x
    |
    = note:      expected struct `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>`
            found type parameter `F`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0308]: mismatched types
   --> $DIR/expected-boxed-future-isnt-pinned.rs:18:5
@@ -40,8 +38,6 @@ LL |     Pin::new(x)
    |
    = note:      expected struct `std::boxed::Box<dyn std::future::Future<Output = i32> + std::marker::Send>`
            found type parameter `F`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
    = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
 
 error[E0277]: `dyn std::future::Future<Output = i32> + std::marker::Send` cannot be unpinned
diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.fixed b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.fixed
new file mode 100644
index 00000000000..8ef7e34ab30
--- /dev/null
+++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.fixed
@@ -0,0 +1,43 @@
+// run-rustfix
+#![allow(unused)] // for the fixed file
+
+trait Trait<T = Self> {
+    type A;
+
+    fn func(&self) -> Self::A;
+}
+
+struct S<T>(T);
+impl<K> S<K> {
+    fn foo<'a, T: Trait + 'a>(&self, _: impl Trait, x: impl Trait<A = usize>, _: T) {
+        qux(x.func()) //~ ERROR mismatched types
+    }
+
+    fn ban<T>(x: T) where T: Trait<A = usize> {
+        qux(x.func()) //~ ERROR mismatched types
+    }
+}
+
+fn foo<'a, T: Trait + 'a>(_: impl Trait, x: impl Trait<A = usize>, _: T) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn bar<T: Trait<A = usize>>(x: T) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn foo2(x: impl Trait<i32, A = usize>) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn bar2<T: Trait<i32, A = usize>>(x: T) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn ban<T>(x: T) where T: Trait<A = usize> {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn qux(_: usize) {}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.rs b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.rs
new file mode 100644
index 00000000000..7bd38d0d45d
--- /dev/null
+++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.rs
@@ -0,0 +1,43 @@
+// run-rustfix
+#![allow(unused)] // for the fixed file
+
+trait Trait<T = Self> {
+    type A;
+
+    fn func(&self) -> Self::A;
+}
+
+struct S<T>(T);
+impl<K> S<K> {
+    fn foo<'a, T: Trait + 'a>(&self, _: impl Trait, x: impl Trait, _: T) {
+        qux(x.func()) //~ ERROR mismatched types
+    }
+
+    fn ban<T>(x: T) where T: Trait {
+        qux(x.func()) //~ ERROR mismatched types
+    }
+}
+
+fn foo<'a, T: Trait + 'a>(_: impl Trait, x: impl Trait, _: T) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn bar<T: Trait>(x: T) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn foo2(x: impl Trait<i32>) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn bar2<T: Trait<i32>>(x: T) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn ban<T>(x: T) where T: Trait {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn qux(_: usize) {}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.stderr b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.stderr
new file mode 100644
index 00000000000..f785f7b84a7
--- /dev/null
+++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.stderr
@@ -0,0 +1,94 @@
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:13:13
+   |
+LL |         qux(x.func())
+   |             ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<impl Trait as Trait>::A`
+help: consider constraining the associated type `<impl Trait as Trait>::A` to `usize`
+   |
+LL |     fn foo<'a, T: Trait + 'a>(&self, _: impl Trait, x: impl Trait<A = usize>, _: T) {
+   |                                                                  ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:17:13
+   |
+LL |         qux(x.func())
+   |             ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<T as Trait>::A`
+help: consider constraining the associated type `<T as Trait>::A` to `usize`
+   |
+LL |     fn ban<T>(x: T) where T: Trait<A = usize> {
+   |                                   ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:22:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<impl Trait as Trait>::A`
+help: consider constraining the associated type `<impl Trait as Trait>::A` to `usize`
+   |
+LL | fn foo<'a, T: Trait + 'a>(_: impl Trait, x: impl Trait<A = usize>, _: T) {
+   |                                                       ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:26:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<T as Trait>::A`
+help: consider constraining the associated type `<T as Trait>::A` to `usize`
+   |
+LL | fn bar<T: Trait<A = usize>>(x: T) {
+   |                ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:30:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<impl Trait<i32> as Trait<i32>>::A`
+help: consider constraining the associated type `<impl Trait<i32> as Trait<i32>>::A` to `usize`
+   |
+LL | fn foo2(x: impl Trait<i32, A = usize>) {
+   |                          ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:34:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<T as Trait<i32>>::A`
+help: consider constraining the associated type `<T as Trait<i32>>::A` to `usize`
+   |
+LL | fn bar2<T: Trait<i32, A = usize>>(x: T) {
+   |                     ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:38:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<T as Trait>::A`
+help: consider constraining the associated type `<T as Trait>::A` to `usize`
+   |
+LL | fn ban<T>(x: T) where T: Trait<A = usize> {
+   |                               ^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs
new file mode 100644
index 00000000000..7465049787f
--- /dev/null
+++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs
@@ -0,0 +1,43 @@
+// These are all the possible variations of this error I could think of for.
+// `trait-with-missing-associated-type-restriction-fixable.rs` contains the subset of these that
+// can be fixed with `rustfix`.
+
+trait Trait<T = Self> {
+    type A;
+
+    fn func(&self) -> Self::A;
+    fn funk(&self, _: Self::A);
+}
+
+fn foo(_: impl Trait, x: impl Trait) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn bar<T: Trait>(x: T) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn foo2(x: impl Trait<i32>) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn bar2<T: Trait<i32>>(x: T) {
+    x.funk(3); //~ ERROR mismatched types
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn baz<D: std::fmt::Debug, T: Trait<A = D>>(x: T) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn bat(x: &mut dyn Trait<(), A = ()>) {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn ban<T>(x: T) where T: Trait {
+    qux(x.func()) //~ ERROR mismatched types
+}
+
+fn qux(_: usize) {}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr
new file mode 100644
index 00000000000..5ae1d45c6b7
--- /dev/null
+++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr
@@ -0,0 +1,103 @@
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:13:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<impl Trait as Trait>::A`
+help: consider constraining the associated type `<impl Trait as Trait>::A` to `usize`
+   |
+LL | fn foo(_: impl Trait, x: impl Trait<A = usize>) {
+   |                                    ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:17:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<T as Trait>::A`
+help: consider constraining the associated type `<T as Trait>::A` to `usize`
+   |
+LL | fn bar<T: Trait<A = usize>>(x: T) {
+   |                ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:21:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<impl Trait<i32> as Trait<i32>>::A`
+help: consider constraining the associated type `<impl Trait<i32> as Trait<i32>>::A` to `usize`
+   |
+LL | fn foo2(x: impl Trait<i32, A = usize>) {
+   |                          ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:25:12
+   |
+LL |     x.funk(3);
+   |            ^ expected associated type, found integer
+   |
+   = note: expected associated type `<T as Trait<i32>>::A`
+                         found type `{integer}`
+help: a method is available that returns `<T as Trait<i32>>::A`
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:8:5
+   |
+LL |     fn func(&self) -> Self::A;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::func`
+help: consider constraining the associated type `<T as Trait<i32>>::A` to `{integer}`
+   |
+LL | fn bar2<T: Trait<i32, A = {integer}>>(x: T) {
+   |                     ^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:26:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<T as Trait<i32>>::A`
+help: consider constraining the associated type `<T as Trait<i32>>::A` to `usize`
+   |
+LL | fn bar2<T: Trait<i32, A = usize>>(x: T) {
+   |                     ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:30:9
+   |
+LL | fn baz<D: std::fmt::Debug, T: Trait<A = D>>(x: T) {
+   |        - this type parameter
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found type parameter `D`
+   |
+   = note:        expected type `usize`
+           found type parameter `D`
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:34:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found `()`
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:38:9
+   |
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found associated type
+   |
+   = note:         expected type `usize`
+           found associated type `<T as Trait>::A`
+help: consider constraining the associated type `<T as Trait>::A` to `usize`
+   |
+LL | fn ban<T>(x: T) where T: Trait<A = usize> {
+   |                               ^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
index 412b4dbda4f..caea791e653 100644
--- a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
+++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
@@ -9,8 +9,6 @@ LL |         Self::TSVariant(());
    |
    = note: expected type parameter `T`
                    found unit type `()`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:15:27
@@ -35,8 +33,6 @@ LL |         Self::<()>::TSVariant(());
    |
    = note: expected type parameter `T`
                    found unit type `()`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:20:16
@@ -61,8 +57,6 @@ LL |         Self::SVariant { v: () };
    |
    = note: expected type parameter `T`
                    found unit type `()`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:28:26
@@ -81,8 +75,6 @@ LL |         Self::SVariant::<()> { v: () };
    |
    = note: expected type parameter `T`
                    found unit type `()`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:31:16
@@ -101,8 +93,6 @@ LL |         Self::<()>::SVariant { v: () };
    |
    = note: expected type parameter `T`
                    found unit type `()`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:34:16
@@ -127,8 +117,6 @@ LL |         Self::<()>::SVariant::<()> { v: () };
    |
    = note: expected type parameter `T`
                    found unit type `()`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:41:26