about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2020-04-13 19:46:34 -0700
committerEsteban Küber <esteban@kuber.com.ar>2020-05-02 18:24:07 -0700
commit31b356619657928113902b975453a5e19371bb25 (patch)
tree3091edeed3d01082c1e4e491a52ee36a5cffb363
parent3a795fba038bf64452abb8c2240fd1221185e274 (diff)
downloadrust-31b356619657928113902b975453a5e19371bb25.tar.gz
rust-31b356619657928113902b975453a5e19371bb25.zip
When a projection is expected, suggest constraining or calling method
-rw-r--r--src/librustc_infer/infer/error_reporting/mod.rs5
-rw-r--r--src/librustc_middle/ty/error.rs198
-rw-r--r--src/test/ui/associated-const/associated-const-generic-obligations.stderr2
-rw-r--r--src/test/ui/associated-types/defaults-in-other-trait-items.rs4
-rw-r--r--src/test/ui/associated-types/defaults-in-other-trait-items.stderr4
-rw-r--r--src/test/ui/associated-types/defaults-specialization.stderr38
-rw-r--r--src/test/ui/associated-types/issue-26681.stderr2
-rw-r--r--src/test/ui/generic-associated-types/iterable.stderr4
-rw-r--r--src/test/ui/issues/issue-32323.stderr6
-rw-r--r--src/test/ui/specialization/specialization-default-projection.stderr2
-rw-r--r--src/test/ui/specialization/specialization-default-types.stderr2
-rw-r--r--src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs4
-rw-r--r--src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr41
13 files changed, 228 insertions, 84 deletions
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index 9de7dcc845f..13c7989e5c8 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/ty/error.rs b/src/librustc_middle/ty/error.rs
index eb5a5702c45..99ea0068fed 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::{BytePos, Span};
+use rustc_span::{BytePos, MultiSpan, Span};
 use rustc_target::spec::abi;
 
 use std::borrow::Cow;
@@ -332,6 +334,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         db: &mut DiagnosticBuilder<'_>,
         err: &TypeError<'tcx>,
+        cause: &ObligationCause<'tcx>,
         sp: Span,
         body_owner_def_id: DefId,
     ) {
@@ -370,7 +373,7 @@ impl<'tcx> TyCtxt<'tcx> {
                                     sp,
                                     "use a float literal",
                                     format!("{}.0", snippet),
-                                    Applicability::MachineApplicable,
+                                    MachineApplicable,
                                 );
                             }
                         }
@@ -451,33 +454,13 @@ impl<T> Trait<T> for X {
                             db.span_label(p_span, "this type parameter");
                         }
                     }
-                    (ty::Projection(_), _) => {
-                        db.note(&format!(
-                            "consider constraining the associated type `{}` to `{}` or calling a \
-                             method that returns `{0}`",
-                            values.expected, values.found,
-                        ));
-                        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() }
-}
-```",
-                            );
-                        }
-                        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(proj_ty)) => {
@@ -485,7 +468,13 @@ impl Trait for X {
                             "consider constraining the associated type `{}` to `{}`",
                             values.found, values.expected,
                         );
-                        if !self.suggest_constraint(db, &msg, body_owner_def_id, proj_ty, values) {
+                        if !self.suggest_constraint(
+                            db,
+                            &msg,
+                            body_owner_def_id,
+                            proj_ty,
+                            values.expected,
+                        ) {
                             db.help(&msg);
                             db.note(
                                 "for more information, visit \
@@ -533,7 +522,7 @@ impl Trait for X {
         msg: &str,
         body_owner_def_id: DefId,
         proj_ty: &ty::ProjectionTy<'tcx>,
-        values: &ExpectedFound<Ty<'tcx>>,
+        ty: Ty<'tcx>,
     ) -> bool {
         let assoc = self.associated_item(proj_ty.item_def_id);
         let trait_ref = proj_ty.trait_ref(*self);
@@ -570,7 +559,7 @@ impl Trait for X {
                             &trait_ref,
                             pred.bounds,
                             &assoc,
-                            values,
+                            ty,
                             msg,
                         ) {
                             return true;
@@ -587,7 +576,7 @@ impl Trait for X {
                             &trait_ref,
                             param.bounds,
                             &assoc,
-                            values,
+                            ty,
                             msg,
                         );
                     }
@@ -597,15 +586,145 @@ impl Trait for X {
         false
     }
 
+    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 mut suggested = false;
+        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);
+
+        let callable_scope = match body_owner {
+            Some(
+                hir::Node::Item(hir::Item {
+                    kind:
+                        hir::ItemKind::Trait(..)
+                        | hir::ItemKind::Impl { .. }
+                        | hir::ItemKind::Const(..)
+                        | hir::ItemKind::Enum(..)
+                        | hir::ItemKind::Struct(..)
+                        | hir::ItemKind::Union(..),
+                    ..
+                })
+                | hir::Node::TraitItem(hir::TraitItem {
+                    kind: hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..),
+                    ..
+                })
+                | hir::Node::ImplItem(hir::ImplItem {
+                    kind: hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(..),
+                    ..
+                }),
+            ) => false,
+            _ => true,
+        };
+        let impl_comparison =
+            matches!(cause_code, ObligationCauseCode::CompareImplMethodObligation { .. });
+        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 {
+            let assoc = self.associated_item(proj_ty.item_def_id);
+            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.
+            let methods: Vec<(Span, String)> = items
+                .items
+                .iter()
+                .filter(|(name, item)| {
+                    ty::AssocKind::Method == 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 = values.expected
+                );
+                for (sp, label) in methods.into_iter() {
+                    span.push_span_label(sp, label);
+                }
+                db.span_help(span, &msg);
+                suggested = true;
+            }
+            // Possibly suggest constraining the associated type to conform to the
+            // found type.
+            suggested |=
+                self.suggest_constraint(db, &msg, body_owner_def_id, proj_ty, values.found);
+        }
+        if !suggested && !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 constrain_associated_type_structured_suggestion(
         &self,
         db: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::TraitRef<'tcx>,
         bounds: hir::GenericBounds<'_>,
         assoc: &ty::AssocItem,
-        values: &ExpectedFound<Ty<'tcx>>,
+        ty: Ty<'tcx>,
         msg: &str,
     ) -> bool {
+        // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
         for bound in bounds {
             match bound {
                 hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => {
@@ -620,14 +739,11 @@ impl Trait for X {
                             let (span, sugg) = if has_params {
                                 let pos = ptr.span.hi() - BytePos(1);
                                 let span = Span::new(pos, pos, ptr.span.ctxt());
-                                (span, format!(", {} = {}", assoc.ident, values.expected))
+                                (span, format!(", {} = {}", assoc.ident, ty))
                             } else {
-                                (
-                                    ptr.span.shrink_to_hi(),
-                                    format!("<{} = {}>", assoc.ident, values.expected),
-                                )
+                                (ptr.span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
                             };
-                            db.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
+                            db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
                             return true;
                         }
                     }
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..6e3ec4ed155 100644
--- a/src/test/ui/associated-const/associated-const-generic-obligations.stderr
+++ b/src/test/ui/associated-const/associated-const-generic-obligations.stderr
@@ -9,7 +9,7 @@ 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`
+   = help: consider constraining the associated type `<T as Foo>::Out` to `&'static str`
    = 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/defaults-in-other-trait-items.rs b/src/test/ui/associated-types/defaults-in-other-trait-items.rs
index 9f2e8aca477..41dc67d6f47 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
@@ -10,7 +10,7 @@ trait Tr {
         //~^ ERROR mismatched types
         //~| NOTE expected associated type, found `()`
         //~| NOTE expected associated type `<Self as Tr>::A`
-        //~| NOTE consider constraining the associated type
+        //~| HELP consider constraining the associated type
         //~| NOTE for more information, visit
     }
 }
@@ -38,7 +38,7 @@ trait AssocConst {
     //~^ ERROR mismatched types
     //~| NOTE expected associated type, found `u8`
     //~| NOTE expected associated type `<Self as AssocConst>::Ty`
-    //~| NOTE consider constraining the associated type
+    //~| HELP consider constraining the associated type
     //~| NOTE for more information, visit
 }
 
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..a5b170d05c4 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
@@ -6,7 +6,7 @@ LL |         let () = p;
    |
    = 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`
+   = help: 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
@@ -17,7 +17,7 @@ LL |     const C: Self::Ty = 0u8;
    |
    = 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`
+   = help: consider constraining the associated type `<Self as AssocConst>::Ty` to `u8`
    = 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..2f3ce832725 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
@@ -23,8 +21,6 @@ LL |     fn make() -> bool { true }
    |
    = 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
@@ -36,7 +32,7 @@ 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`
+   = help: 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
@@ -49,7 +45,7 @@ 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
@@ -62,7 +58,7 @@ 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`
+   = help: 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
@@ -75,8 +71,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 +87,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 +103,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 +119,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/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 4a839ac4bcb..6e754621225 100644
--- a/src/test/ui/generic-associated-types/iterable.stderr
+++ b/src/test/ui/generic-associated-types/iterable.stderr
@@ -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/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/specialization/specialization-default-projection.stderr b/src/test/ui/specialization/specialization-default-projection.stderr
index 4344fe23bbc..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
diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr
index d66aaa96274..4dccf9ad9ab 100644
--- a/src/test/ui/specialization/specialization-default-types.stderr
+++ b/src/test/ui/specialization/specialization-default-types.stderr
@@ -8,7 +8,7 @@ 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`
+   = help: 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
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
index 1166785d739..7465049787f 100644
--- a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs
+++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs
@@ -6,6 +6,7 @@ trait Trait<T = Self> {
     type A;
 
     fn func(&self) -> Self::A;
+    fn funk(&self, _: Self::A);
 }
 
 fn foo(_: impl Trait, x: impl Trait) {
@@ -21,6 +22,7 @@ fn foo2(x: impl Trait<i32>) {
 }
 
 fn bar2<T: Trait<i32>>(x: T) {
+    x.funk(3); //~ ERROR mismatched types
     qux(x.func()) //~ ERROR mismatched types
 }
 
@@ -29,7 +31,7 @@ fn baz<D: std::fmt::Debug, T: Trait<A = D>>(x: T) {
 }
 
 fn bat(x: &mut dyn Trait<(), A = ()>) {
-    qux(x) //~ ERROR mismatched types
+    qux(x.func()) //~ ERROR mismatched types
 }
 
 fn ban<T>(x: T) where T: Trait {
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
index 08788db6ec9..5ae1d45c6b7 100644
--- a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr
+++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:12:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:13:9
    |
 LL |     qux(x.func())
    |         ^^^^^^^^ expected `usize`, found associated type
@@ -12,7 +12,7 @@ LL | fn foo(_: impl Trait, x: impl Trait<A = usize>) {
    |                                    ^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:16:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:17:9
    |
 LL |     qux(x.func())
    |         ^^^^^^^^ expected `usize`, found associated type
@@ -25,7 +25,7 @@ LL | fn bar<T: Trait<A = usize>>(x: T) {
    |                ^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:20:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:21:9
    |
 LL |     qux(x.func())
    |         ^^^^^^^^ expected `usize`, found associated type
@@ -38,7 +38,25 @@ LL | fn foo2(x: impl Trait<i32, A = usize>) {
    |                          ^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:24:9
+  --> $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
@@ -51,7 +69,7 @@ LL | fn bar2<T: Trait<i32, A = usize>>(x: T) {
    |                     ^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:28:9
+  --> $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
@@ -62,16 +80,13 @@ LL |     qux(x.func())
            found type parameter `D`
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:32:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:34:9
    |
-LL |     qux(x)
-   |         ^ expected `usize`, found mutable reference
-   |
-   = note:           expected type `usize`
-           found mutable reference `&mut dyn Trait<(), A = ()>`
+LL |     qux(x.func())
+   |         ^^^^^^^^ expected `usize`, found `()`
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:36:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:38:9
    |
 LL |     qux(x.func())
    |         ^^^^^^^^ expected `usize`, found associated type
@@ -83,6 +98,6 @@ 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
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0308`.