Skip to content

Commit 4551a3e

Browse files
committed
Detect when trait is implemented for type and suggest importing it
Fix #57457.
1 parent 93e62a2 commit 4551a3e

File tree

2 files changed

+62
-28
lines changed

2 files changed

+62
-28
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+53-16
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use rustc_span::def_id::DefIdSet;
3636
use rustc_span::symbol::{kw, sym, Ident};
3737
use rustc_span::Symbol;
3838
use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span};
39+
use rustc_trait_selection::infer::InferCtxtExt;
3940
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
4041
use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
4142
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -193,7 +194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
193194
.span_if_local(def_id)
194195
.unwrap_or_else(|| self.tcx.def_span(def_id));
195196
err.span_label(sp, format!("private {kind} defined here"));
196-
self.suggest_valid_traits(&mut err, out_of_scope_traits);
197+
self.suggest_valid_traits(&mut err, out_of_scope_traits, true);
197198
err.emit();
198199
}
199200

@@ -2450,6 +2451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24502451
&self,
24512452
err: &mut Diagnostic,
24522453
valid_out_of_scope_traits: Vec<DefId>,
2454+
explain: bool,
24532455
) -> bool {
24542456
if !valid_out_of_scope_traits.is_empty() {
24552457
let mut candidates = valid_out_of_scope_traits;
@@ -2462,7 +2464,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24622464
.find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
24632465
.copied();
24642466

2465-
err.help("items from traits can only be used if the trait is in scope");
2467+
if explain {
2468+
err.help("items from traits can only be used if the trait is in scope");
2469+
}
24662470
let msg = format!(
24672471
"the following {traits_are} implemented but not in scope; \
24682472
perhaps add a `use` for {one_of_them}:",
@@ -2679,7 +2683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26792683
}
26802684
}
26812685
}
2682-
if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
2686+
if self.suggest_valid_traits(err, valid_out_of_scope_traits, true) {
26832687
return;
26842688
}
26852689

@@ -2959,26 +2963,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
29592963
match &potential_candidates[..] {
29602964
[] => {}
29612965
[trait_info] if trait_info.def_id.is_local() => {
2962-
err.subdiagnostic(CandidateTraitNote {
2963-
span: self.tcx.def_span(trait_info.def_id),
2964-
trait_name: self.tcx.def_path_str(trait_info.def_id),
2965-
item_name,
2966-
action_or_ty: if trait_missing_method {
2967-
"NONE".to_string()
2968-
} else {
2969-
param_type.map_or_else(
2970-
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
2971-
ToString::to_string,
2972-
)
2973-
},
2974-
});
2966+
let args =
2967+
ty::GenericArgs::for_item(self.tcx, trait_info.def_id, |param, _| {
2968+
if param.index == 0 {
2969+
rcvr_ty.into()
2970+
} else {
2971+
self.infcx.var_for_def(span, param)
2972+
}
2973+
});
2974+
if self
2975+
.infcx
2976+
.type_implements_trait(trait_info.def_id, args, self.param_env)
2977+
.must_apply_modulo_regions()
2978+
&& param_type.is_none()
2979+
{
2980+
self.suggest_valid_traits(err, vec![trait_info.def_id], false);
2981+
} else {
2982+
err.subdiagnostic(CandidateTraitNote {
2983+
span: self.tcx.def_span(trait_info.def_id),
2984+
trait_name: self.tcx.def_path_str(trait_info.def_id),
2985+
item_name,
2986+
action_or_ty: if trait_missing_method {
2987+
"NONE".to_string()
2988+
} else {
2989+
param_type.map_or_else(
2990+
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
2991+
ToString::to_string,
2992+
)
2993+
},
2994+
});
2995+
}
29752996
}
29762997
trait_infos => {
29772998
let mut msg = message(param_type.map_or_else(
29782999
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
29793000
|param| format!("restrict type parameter `{param}` with"),
29803001
));
29813002
for (i, trait_info) in trait_infos.iter().enumerate() {
3003+
let args =
3004+
ty::GenericArgs::for_item(self.tcx, trait_info.def_id, |param, _| {
3005+
if param.index == 0 {
3006+
rcvr_ty.into()
3007+
} else {
3008+
self.infcx.var_for_def(span, param)
3009+
}
3010+
});
3011+
if self
3012+
.infcx
3013+
.type_implements_trait(trait_info.def_id, args, self.param_env)
3014+
.must_apply_modulo_regions()
3015+
&& param_type.is_none()
3016+
{
3017+
self.suggest_valid_traits(err, vec![trait_info.def_id], false);
3018+
}
29823019
msg.push_str(&format!(
29833020
"\ncandidate #{}: `{}`",
29843021
i + 1,

tests/ui/traits/item-privacy.stderr

+9-12
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ LL | S.a();
88
| ^ method not found in `S`
99
|
1010
= help: items from traits can only be used if the trait is implemented and in scope
11-
note: `method::A` defines an item `a`, perhaps you need to implement it
12-
--> $DIR/item-privacy.rs:6:5
11+
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
12+
|
13+
LL + use method::A;
1314
|
14-
LL | trait A {
15-
| ^^^^^^^
1615

1716
error[E0599]: no method named `b` found for struct `S` in the current scope
1817
--> $DIR/item-privacy.rs:68:7
@@ -51,11 +50,10 @@ LL | S::a(&S);
5150
| ^ function or associated item not found in `S`
5251
|
5352
= help: items from traits can only be used if the trait is implemented and in scope
54-
note: `method::A` defines an item `a`, perhaps you need to implement it
55-
--> $DIR/item-privacy.rs:6:5
53+
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
54+
|
55+
LL + use method::A;
5656
|
57-
LL | trait A {
58-
| ^^^^^^^
5957

6058
error[E0599]: no function or associated item named `b` found for struct `S` in the current scope
6159
--> $DIR/item-privacy.rs:80:8
@@ -91,11 +89,10 @@ LL | S::A;
9189
| ^ associated item not found in `S`
9290
|
9391
= help: items from traits can only be used if the trait is implemented and in scope
94-
note: `assoc_const::A` defines an item `A`, perhaps you need to implement it
95-
--> $DIR/item-privacy.rs:24:5
92+
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
93+
|
94+
LL + use assoc_const::A;
9695
|
97-
LL | trait A {
98-
| ^^^^^^^
9996

10097
error[E0599]: no associated item named `B` found for struct `S` in the current scope
10198
--> $DIR/item-privacy.rs:98:8

0 commit comments

Comments
 (0)