1
Fork 0

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 @@ use std::iter;
pub enum TypeAnnotationNeeded { pub enum TypeAnnotationNeeded {
/// ```compile_fail,E0282 /// ```compile_fail,E0282
/// let x = "hello".chars().rev().collect(); /// let x;
/// ``` /// ```
E0282, E0282,
/// An implementation cannot be chosen unambiguously because of lack of information. /// An implementation cannot be chosen unambiguously because of lack of information.

View file

@ -25,7 +25,7 @@ use rustc_errors::{
MultiSpan, Style, MultiSpan, Style,
}; };
use rustc_hir as hir; 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::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::Visitor;
use rustc_hir::{GenericParam, Item, Node}; use rustc_hir::{GenericParam, Item, Node};
@ -2453,12 +2453,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& let [ && let [
.., ..,
trait_path_segment @ hir::PathSegment { 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 { hir::PathSegment {
ident: assoc_item_name, ident: assoc_item_name,
res: rustc_hir::def::Res::Def(_, item_id), res: Res::Def(_, item_id),
.. ..
} }
] = path.segments ] = path.segments
@ -2469,7 +2469,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let (verb, noun) = match self.tcx.associated_item(item_id).kind { let (verb, noun) = match self.tcx.associated_item(item_id).kind {
ty::AssocKind::Const => ("refer to the", "constant"), ty::AssocKind::Const => ("refer to the", "constant"),
ty::AssocKind::Fn => ("call", "function"), 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 // Replace the more general E0283 with a more specific error
@ -2477,37 +2479,58 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err = self.tcx.sess.struct_span_err_with_code( err = self.tcx.sess.struct_span_err_with_code(
span, span,
format!( 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), rustc_errors::error_code!(E0790),
); );
if let Some(local_def_id) = data.trait_ref.def_id.as_local() 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(hir::Node::Item(hir::Item {
&& let Some(method_ref) = trait_item_refs.iter().find(|item_ref| item_ref.ident == *assoc_item_name) { ident: trait_name,
err.span_label(method_ref.span, format!("`{trait_name}::{assoc_item_name}` defined here")); 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")); err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id); let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
if trait_impls.blanket_impls().is_empty() if let Some(impl_def_id) =
&& let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next() 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. // If there is only one implementation of the trait, suggest using it.
// Otherwise, use a placeholder comment for the implementation. // Otherwise, use a placeholder comment for the implementation.
let (message, impl_suggestion) = if non_blanket_impl_count == 1 {( let (message, self_type) = 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()) "use the fully-qualified path to the only available \
)} else { implementation",
("use a fully-qualified path to a specific available implementation", format!(
"</* self type */ as ".to_string() "{}",
)}; 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![( let mut suggestions = vec![(
path.span.shrink_to_lo(), path.span.shrink_to_lo(),
impl_suggestion format!("<{self_type} as "),
)]; )];
if let Some(generic_arg) = trait_path_segment.args { if let Some(generic_arg) = trait_path_segment.args {
let between_span = trait_path_segment.ident.span.between(generic_arg.span_ext); 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")); LL | return Err(From::from("foo"));
| ^^^^^^^^^^ cannot call associated function of trait | ^^^^^^^^^^ 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 error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/cross-return-site-inference.rs:44:9 --> $DIR/cross-return-site-inference.rs:44:9
| |
LL | Err(From::from("foo")) LL | Err(From::from("foo"))
| ^^^^^^^^^^ cannot call associated function of trait | ^^^^^^^^^^ 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 error: aborting due to 3 previous errors