Show suggestion for <SelfTy as Trait>::assoc_fn in more cases and fmt code

This commit is contained in:
Esteban Küber 2023-08-14 13:26:11 +00:00
parent 91b9ffeab0
commit 7313c10774
3 changed files with 53 additions and 20 deletions

View File

@ -27,7 +27,7 @@
pub enum TypeAnnotationNeeded {
/// ```compile_fail,E0282
/// let x = "hello".chars().rev().collect();
/// let x;
/// ```
E0282,
/// An implementation cannot be chosen unambiguously because of lack of information.

View File

@ -25,7 +25,7 @@
MultiSpan, Style,
};
use rustc_hir as hir;
use rustc_hir::def::Namespace;
use rustc_hir::def::{DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{GenericParam, Item, Node};
@ -2453,12 +2453,12 @@ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
&& let [
..,
trait_path_segment @ hir::PathSegment {
res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id),
res: Res::Def(DefKind::Trait, trait_id),
..
},
hir::PathSegment {
ident: assoc_item_name,
res: rustc_hir::def::Res::Def(_, item_id),
res: Res::Def(_, item_id),
..
}
] = path.segments
@ -2469,7 +2469,9 @@ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
let (verb, noun) = match self.tcx.associated_item(item_id).kind {
ty::AssocKind::Const => ("refer to the", "constant"),
ty::AssocKind::Fn => ("call", "function"),
ty::AssocKind::Type => ("refer to the", "type"), // this is already covered by E0223, but this single match arm doesn't hurt here
// This is already covered by E0223, but this following single match
// arm doesn't hurt here.
ty::AssocKind::Type => ("refer to the", "type"),
};
// Replace the more general E0283 with a more specific error
@ -2477,37 +2479,58 @@ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
err = self.tcx.sess.struct_span_err_with_code(
span,
format!(
"cannot {verb} associated {noun} on trait without specifying the corresponding `impl` type",
"cannot {verb} associated {noun} on trait without specifying the \
corresponding `impl` type",
),
rustc_errors::error_code!(E0790),
);
if let Some(local_def_id) = data.trait_ref.def_id.as_local()
&& let Some(hir::Node::Item(hir::Item { ident: trait_name, kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), .. })) = self.tcx.hir().find_by_def_id(local_def_id)
&& let Some(method_ref) = trait_item_refs.iter().find(|item_ref| item_ref.ident == *assoc_item_name) {
err.span_label(method_ref.span, format!("`{trait_name}::{assoc_item_name}` defined here"));
&& let Some(hir::Node::Item(hir::Item {
ident: trait_name,
kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
..
})) = self.tcx.hir().find_by_def_id(local_def_id)
&& let Some(method_ref) = trait_item_refs
.iter()
.find(|item_ref| item_ref.ident == *assoc_item_name)
{
err.span_label(
method_ref.span,
format!("`{trait_name}::{assoc_item_name}` defined here"),
);
}
err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
if trait_impls.blanket_impls().is_empty()
&& let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next()
if let Some(impl_def_id) =
trait_impls.non_blanket_impls().values().flatten().next()
{
let non_blanket_impl_count = trait_impls.non_blanket_impls().values().flatten().count();
let non_blanket_impl_count =
trait_impls.non_blanket_impls().values().flatten().count();
// If there is only one implementation of the trait, suggest using it.
// Otherwise, use a placeholder comment for the implementation.
let (message, impl_suggestion) = if non_blanket_impl_count == 1 {(
"use the fully-qualified path to the only available implementation",
format!("<{} as ", self.tcx.type_of(impl_def_id).instantiate_identity())
)} else {
("use a fully-qualified path to a specific available implementation",
"</* self type */ as ".to_string()
)};
let (message, self_type) = if non_blanket_impl_count == 1 {
(
"use the fully-qualified path to the only available \
implementation",
format!(
"{}",
self.tcx.type_of(impl_def_id).instantiate_identity()
),
)
} else {
(
"use a fully-qualified path to a specific available \
implementation",
"/* self type */".to_string(),
)
};
let mut suggestions = vec![(
path.span.shrink_to_lo(),
impl_suggestion
format!("<{self_type} as "),
)];
if let Some(generic_arg) = trait_path_segment.args {
let between_span = trait_path_segment.ident.span.between(generic_arg.span_ext);

View File

@ -14,12 +14,22 @@ error[E0790]: cannot call associated function on trait without specifying the co
|
LL | return Err(From::from("foo"));
| ^^^^^^^^^^ cannot call associated function of trait
|
help: use a fully-qualified path to a specific available implementation
|
LL | return Err(</* self type */ as From>::from("foo"));
| +++++++++++++++++++ +
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/cross-return-site-inference.rs:44:9
|
LL | Err(From::from("foo"))
| ^^^^^^^^^^ cannot call associated function of trait
|
help: use a fully-qualified path to a specific available implementation
|
LL | Err(</* self type */ as From>::from("foo"))
| +++++++++++++++++++ +
error: aborting due to 3 previous errors