Skip to content

Commit 4a71828

Browse files
Added shadowed hint for overlapping associated types
Added help message to suggest renaming Added rename help message on subtrait Remove rename suggestions on unrelated associated types Added ui test Removed call to filter_by_name_unhygienic
1 parent 9c8a269 commit 4a71828

File tree

4 files changed

+107
-1
lines changed

4 files changed

+107
-1
lines changed

compiler/rustc_hir_analysis/src/astconv/errors.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorG
99
use rustc_hir as hir;
1010
use rustc_hir::def_id::{DefId, LocalDefId};
1111
use rustc_infer::traits::FulfillmentError;
12-
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt};
12+
use rustc_middle::ty::{self, suggest_constraining_type_param, AssocItem, AssocKind, Ty, TyCtxt};
1313
use rustc_session::parse::feature_err;
1414
use rustc_span::edit_distance::find_best_match_for_name;
1515
use rustc_span::symbol::{sym, Ident};
@@ -513,6 +513,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
513513
if associated_types.values().all(|v| v.is_empty()) {
514514
return;
515515
}
516+
516517
let tcx = self.tcx();
517518
// FIXME: Marked `mut` so that we can replace the spans further below with a more
518519
// appropriate one, but this should be handled earlier in the span assignment.
@@ -585,6 +586,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
585586
}
586587
}
587588

589+
// We get all the associated items that _are_ set,
590+
// so that we can check if any of their names match one of the ones we are missing.
591+
// This would mean that they are shadowing the associated type we are missing,
592+
// and we can then use their span to indicate this to the user.
593+
let bound_names = trait_bounds
594+
.iter()
595+
.filter_map(|poly_trait_ref| {
596+
poly_trait_ref.trait_ref.path.segments.last().and_then(|path| path.args)
597+
})
598+
.flat_map(|args| {
599+
args.bindings.iter().map(|binding| {
600+
let ident = binding.ident;
601+
let trait_def = poly_trait_ref.trait_ref.path.res.opt_def_id();
602+
let assoc_item = trait_def.and_then(|did| {
603+
tcx.associated_items(did).find_by_name_and_kinds(
604+
tcx,
605+
ident,
606+
&[AssocKind::Fn, AssocKind::Type, AssocKind::Const],
607+
did,
608+
);
609+
});
610+
(ident.name, assoc_item)
611+
})
612+
})
613+
.collect::<FxHashMap<Symbol, Option<&AssocItem>>>();
614+
588615
let mut names = names
589616
.into_iter()
590617
.map(|(trait_, mut assocs)| {
@@ -614,6 +641,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
614641
pluralize!(names_len),
615642
names,
616643
);
644+
let mut rename_suggestions = vec![];
617645
let mut suggestions = vec![];
618646
let mut types_count = 0;
619647
let mut where_constraints = vec![];
@@ -625,23 +653,47 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
625653
*names.entry(item.name).or_insert(0) += 1;
626654
}
627655
let mut dupes = false;
656+
let mut shadows = false;
628657
for item in assoc_items {
629658
let prefix = if names[&item.name] > 1 {
630659
let trait_def_id = item.container_id(tcx);
631660
dupes = true;
632661
format!("{}::", tcx.def_path_str(trait_def_id))
662+
} else if bound_names.contains_key(&item.name) {
663+
let trait_def_id = item.container_id(tcx);
664+
shadows = true;
665+
format!("{}::", tcx.def_path_str(trait_def_id))
633666
} else {
634667
String::new()
635668
};
636669
if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
637670
err.span_label(sp, format!("`{}{}` defined here", prefix, item.name));
638671
}
672+
673+
if let Some(Some(assoc_item)) = bound_names.get(&item.name) {
674+
err.span_label(
675+
tcx.def_span(assoc_item.def_id),
676+
format!("`{}{}` shadowed here", prefix, item.name),
677+
);
678+
}
639679
}
640680
if potential_assoc_types.len() == assoc_items.len() {
641681
// When the amount of missing associated types equals the number of
642682
// extra type arguments present. A suggesting to replace the generic args with
643683
// associated types is already emitted.
644684
already_has_generics_args_suggestion = true;
685+
} else if shadows {
686+
for item in assoc_items {
687+
if let Some(Some(assoc_item)) = bound_names.get(&item.name) {
688+
if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
689+
rename_suggestions.push(sp);
690+
}
691+
692+
if let Some(sp) = tcx.hir().span_if_local(assoc_item.def_id) {
693+
rename_suggestions.push(sp);
694+
}
695+
}
696+
}
645697
} else if let (Ok(snippet), false) =
646698
(tcx.sess.source_map().span_to_snippet(*span), dupes)
647699
{
@@ -725,6 +777,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
725777
err.span_help(where_constraints, where_msg);
726778
}
727779
}
780+
781+
for span in rename_suggestions {
782+
err.span_help(span, "consider renaming this associated type");
783+
}
728784
err.emit();
729785
}
730786
}

tests/ui/associated-type-bounds/overlaping-bound-suggestion.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ LL | inner: <IntoIterator<Item: IntoIterator<Item: >>::IntoIterator as Item>
66
| | |
77
| | associated types `Item`, `IntoIter` must be specified
88
| associated types `Item`, `IntoIter` must be specified
9+
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
10+
|
11+
= note: `IntoIterator::Item` shadowed here
12+
|
13+
= note: `IntoIterator::Item` shadowed here
914

1015
error[E0223]: ambiguous associated type
1116
--> $DIR/overlaping-bound-suggestion.rs:7:13
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Test Setting the value of an associated type
2+
// that is shadowed from a supertrait
3+
4+
pub trait Super {
5+
type X;
6+
}
7+
8+
pub trait Sub: Super {
9+
type X; //~INFO shadowed
10+
}
11+
12+
//~ ERROR missing type
13+
impl<T> Clone for Box<dyn Sub<X = T>> {
14+
fn clone(&self) -> Self {
15+
unimplemented!();
16+
}
17+
}
18+
19+
pub fn main() {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error[E0191]: the value of the associated type `X` in `Super` must be specified
2+
--> $DIR/associated-type-shadowed-from-supertrait.rs:13:27
3+
|
4+
LL | type X;
5+
| ------ `Super::X` defined here
6+
...
7+
LL | type X;
8+
| ------ `Super::X` shadowed here
9+
...
10+
LL | impl<T> Clone for Box<dyn Sub<X = T>> {
11+
| ^^^^^^^^^^ associated type `X` must be specified
12+
|
13+
help: consider renaming this associated type
14+
--> $DIR/associated-type-shadowed-from-supertrait.rs:5:5
15+
|
16+
LL | type X;
17+
| ^^^^^^
18+
help: consider renaming this associated type
19+
--> $DIR/associated-type-shadowed-from-supertrait.rs:9:5
20+
|
21+
LL | type X;
22+
| ^^^^^^
23+
24+
error: aborting due to previous error
25+
26+
For more information about this error, try `rustc --explain E0191`.

0 commit comments

Comments
 (0)