Rollup merge of #116862 - estebank:issue-57457, r=oli-obk

Detect when trait is implemented for type and suggest importing it

Fix #57457.
This commit is contained in:
Matthias Krüger 2023-10-30 21:03:37 +01:00 committed by GitHub
commit c299595379
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 28 deletions

View File

@ -35,6 +35,7 @@
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@ -192,7 +193,7 @@ pub fn report_method_error(
.span_if_local(def_id)
.unwrap_or_else(|| self.tcx.def_span(def_id));
err.span_label(sp, format!("private {kind} defined here"));
self.suggest_valid_traits(&mut err, out_of_scope_traits);
self.suggest_valid_traits(&mut err, out_of_scope_traits, true);
err.emit();
}
@ -2464,6 +2465,7 @@ fn suggest_valid_traits(
&self,
err: &mut Diagnostic,
valid_out_of_scope_traits: Vec<DefId>,
explain: bool,
) -> bool {
if !valid_out_of_scope_traits.is_empty() {
let mut candidates = valid_out_of_scope_traits;
@ -2476,7 +2478,9 @@ fn suggest_valid_traits(
.find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
.copied();
err.help("items from traits can only be used if the trait is in scope");
if explain {
err.help("items from traits can only be used if the trait is in scope");
}
let msg = format!(
"the following {traits_are} implemented but not in scope; \
perhaps add a `use` for {one_of_them}:",
@ -2693,7 +2697,7 @@ fn suggest_traits_to_import(
}
}
}
if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
if self.suggest_valid_traits(err, valid_out_of_scope_traits, true) {
return;
}
@ -2970,22 +2974,39 @@ enum Introducer {
(candidates, Vec::new())
};
let impls_trait = |def_id: DefId| {
let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| {
if param.index == 0 {
rcvr_ty.into()
} else {
self.infcx.var_for_def(span, param)
}
});
self.infcx
.type_implements_trait(def_id, args, self.param_env)
.must_apply_modulo_regions()
&& param_type.is_none()
};
match &potential_candidates[..] {
[] => {}
[trait_info] if trait_info.def_id.is_local() => {
err.subdiagnostic(CandidateTraitNote {
span: self.tcx.def_span(trait_info.def_id),
trait_name: self.tcx.def_path_str(trait_info.def_id),
item_name,
action_or_ty: if trait_missing_method {
"NONE".to_string()
} else {
param_type.map_or_else(
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
ToString::to_string,
)
},
});
if impls_trait(trait_info.def_id) {
self.suggest_valid_traits(err, vec![trait_info.def_id], false);
} else {
err.subdiagnostic(CandidateTraitNote {
span: self.tcx.def_span(trait_info.def_id),
trait_name: self.tcx.def_path_str(trait_info.def_id),
item_name,
action_or_ty: if trait_missing_method {
"NONE".to_string()
} else {
param_type.map_or_else(
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
ToString::to_string,
)
},
});
}
}
trait_infos => {
let mut msg = message(param_type.map_or_else(
@ -2993,6 +3014,9 @@ enum Introducer {
|param| format!("restrict type parameter `{param}` with"),
));
for (i, trait_info) in trait_infos.iter().enumerate() {
if impls_trait(trait_info.def_id) {
self.suggest_valid_traits(err, vec![trait_info.def_id], false);
}
msg.push_str(&format!(
"\ncandidate #{}: `{}`",
i + 1,

View File

@ -8,11 +8,10 @@ LL | S.a();
| ^ method not found in `S`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `method::A` defines an item `a`, perhaps you need to implement it
--> $DIR/item-privacy.rs:6:5
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
LL + use method::A;
|
LL | trait A {
| ^^^^^^^
error[E0599]: no method named `b` found for struct `S` in the current scope
--> $DIR/item-privacy.rs:68:7
@ -51,11 +50,10 @@ LL | S::a(&S);
| ^ function or associated item not found in `S`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `method::A` defines an item `a`, perhaps you need to implement it
--> $DIR/item-privacy.rs:6:5
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
LL + use method::A;
|
LL | trait A {
| ^^^^^^^
error[E0599]: no function or associated item named `b` found for struct `S` in the current scope
--> $DIR/item-privacy.rs:80:8
@ -91,11 +89,10 @@ LL | S::A;
| ^ associated item not found in `S`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `assoc_const::A` defines an item `A`, perhaps you need to implement it
--> $DIR/item-privacy.rs:24:5
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
LL + use assoc_const::A;
|
LL | trait A {
| ^^^^^^^
error[E0599]: no associated item named `B` found for struct `S` in the current scope
--> $DIR/item-privacy.rs:98:8