Change:
I am working through this and is with such a challenge: So I tried it. : note: the method exists but the following trait bounds were not satisfied: help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item , perhaps you need to implement one of them: help: candidate : help: candidate : help: candidate : The minimal code that produces the error message is The error message tells me that I need to implement a trait. Since I have already implemented it, I would be confused by the error message, and misled by it from the actual reason, failure to declare it in the signature. I think it would be better if the message is changed to note: the method exists but the following trait bounds were not satisfied: help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item , perhaps you need to declare one of them for : help: candidate : help: candidate : help: candidate : On the other hand, if I actually drop the block , but declare in the signature, the error message is label: the trait is not implemented for note: required by which is straightforward enough.
Today, we suggest that the method exists, but we somehow fail to see that it exists on Minimum in the first note and then latter note it in the second note.
It still doesn't help a lot IMO... since the problem is the bound isn't declared in the signature, and nothing regarding declaration is mentioned. maybe change to
I think that can be easily fixed by checking if is not empty and using a different message in that case Do you have suggestion how the error should look like? Does that sound ok?
I don't think your error message communicates much more than the current one. I also think the error message is already straightforward enough. From my perspective, I think the problem is one of asymmetry in the help section. It mentioned "items from traits can only be used if the trait is implemented and in scope", but then went on to only suggest "perhaps you need to implement one of them". Excuse me for being insistent on this, but I believe the best way is to remind that to bring function into scope the trait bound needs to be declared as well as implemented.
LOL this is actually a duplicate of . There's even a .
I think we're talking about different cases (which may be another reason to split or reword the message). For methods the message says "method not found", but adds a note saying "the method exists", which I really don't like, because it's very easy to miss the nuance and interpret the message as nonsense "the method does not exist" "but it exists". I've explained more here:
With the output will be:

Discussion:
} } <del> fn suggest_traits_to_import<'b>(&self, err: &mut DiagnosticBuilder<'_>, span: Span, rcvr_ty: Ty<'tcx>, item_name: ast::Ident, source: SelfSource<'b>, valid_out_of_scope_traits: Vec<DefId>) { </del> <ins> fn suggest_traits_to_import<'b>( &self, err: &mut DiagnosticBuilder<'_>, span: Span, rcvr_ty: Ty<'tcx>, item_name: ast::Ident, source: SelfSource<'b>, valid_out_of_scope_traits: Vec<DefId>, ) { </ins> if self.suggest_valid_traits(err, valid_out_of_scope_traits) { return; }

candidates.sort_by(|a, b| a.cmp(b).reverse()); candidates.dedup(); <del> // FIXME #21673: this help message could be tuned to the case // of a type parameter: suggest adding a trait bound rather // than implementing. err.help("items from traits can only be used if the trait is implemented and in scope"); let mut msg = format!("the following {traits_define} an item `{name}`,  perhaps you need to implement {one_of_them}:", traits_define = if candidates.len() == 1 { "trait defines" } else { "traits define" }, one_of_them = if candidates.len() == 1 { "it" } else { "one of them" }, name = item_name); for (i, trait_info) in candidates.iter().enumerate() { msg.push_str(&format!("ncandidate #{}: `{}`", i + 1, self.tcx.def_path_str(trait_info.def_id))); </del> <ins> let param_type = match rcvr_ty.sty { ty::Param(param) => Some(param), ty::Ref(_, ty, _) => match ty.sty { ty::Param(param) => Some(param), _ => None, } _ => None, }; err.help(if param_type.is_some() { "items from traits can only be used if the type parameter is bounded by the trait" } else { "items from traits can only be used if the trait is implemented and in scope" }); let mut msg = format!( "the following {traits_define} an item `{name}`, perhaps you need to {action}  {one_of_them}:", traits_define = if candidates.len() == 1 { "trait defines" } else { "traits define" }, action = if let Some(param) = param_type { format!("restrict type parameter `{}` with", param) } else { "implement".to_string() }, one_of_them = if candidates.len() == 1 { "it" } else { "one of them" }, name = item_name, ); // Obtain the span for `param` and use it for a structured suggestion. let mut suggested = false; if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) { let table = table.borrow(); if let Some(did) = table.local_id_root { let generics = self.tcx.generics_of(did); let type_param = generics.type_param(param, self.tcx); let hir = &self.tcx.hir(); if let Some(id) = hir.as_local_hir_id(type_param.def_id) { // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: FooBar`, // instead we suggest `T: Foo + Bar` in that case. let mut has_bounds = false; if let Node::GenericParam(ref param) = hir.get(id) { has_bounds = !param.bounds.is_empty(); } let sp = hir.span(id); // `sp` only covers `T`, change it so that it covers // `T:` when appropriate let sp = if has_bounds { sp.to(self.tcx .sess .source_map() .next_point(self.tcx.sess.source_map().next_point(sp))) } else { sp }; // FIXME: contrast `t.def_id` against `param.bounds` to not suggest traits // already there. That can happen when the cause is that we're in a const // scope or associated function used as a method. err.span_suggestions( sp, &msg[..], candidates.iter().map(|t| format!( "{}: {}{}", param, self.tcx.def_path_str(t.def_id), if has_bounds { " +"} else { "" }, )), Applicability::MaybeIncorrect, ); suggested = true; } }; } if !suggested { for (i, trait_info) in candidates.iter().enumerate() { msg.push_str(&format!( "ncandidate #{}: `{}`", i + 1, self.tcx.def_path_str(trait_info.def_id), )); } err.note(&msg[..]); </ins> } <del> err.note(&msg[..]); </del> } }

LL |     entries: [T; D::dim()], |                     ^^^ function or associated item not found in `D` | <del> = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `dim`, perhaps you need to implement it: candidate #1: `Dim` </del> <ins> = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `dim`, perhaps you need to restrict type parameter `D` with it: | LL | pub struct Vector<T, D: Dim + Dim> { |                      ^^^^^^^^ </ins> error: aborting due to previous error

LL |     fn is_str() -> bool { |     ^^^^^^^^^^^^^^^^^^^ = help: to disambiguate the method call, write `ManyImplTrait::is_str(t)` instead <del> = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `is_str`, perhaps you need to implement it: candidate #1: `ManyImplTrait` </del> <ins> = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `is_str`, perhaps you need to restrict type parameter `T` with it: | LL | fn param_bound<T: ManyImplTrait + ManyImplTrait>(t: T) -> bool { |                ^^^^^^^^^^^^^^^^^^ </ins> error: aborting due to 3 previous errors

<ins> trait Foo { fn method(&self) {} } fn call_method<T: std::fmt::Debug>(x: &T) { x.method() //~ ERROR E0599 } fn call_method_2<T>(x: T) { x.method() //~ ERROR E0599 } fn main() {} </ins>

<ins> error[E0599]: no method named `method` found for type `&T` in the current scope --> $DIR/issue-21673.rs:6:7 | LL |     x.method() |       ^^^^^^ | = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it: | LL | fn call_method<T: Foo + std::fmt::Debug>(x: &T) { |                ^^^^^^^^ error[E0599]: no method named `method` found for type `T` in the current scope --> $DIR/issue-21673.rs:10:7 | LL |     x.method() |       ^^^^^^ | = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it: | LL | fn call_method_2<T: Foo>(x: T) { |                  ^^^^^^ error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0599`. </ins>