Skip to content

Commit 1404dbd

Browse files
Point out shadowed associated types
Shadowing the associated type of a supertrait is allowed. This however makes it impossible to set the associated type of the supertrait in a dyn object. This PR makes the error message for that case clearer, like adding a note that shadowing is happening, as well as suggesting renaming of one of the associated types.
1 parent 0b8a61b commit 1404dbd

5 files changed

+119
-4
lines changed

compiler/rustc_hir_analysis/src/astconv/errors.rs

+58-4
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};
@@ -509,6 +509,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
509509
if associated_types.values().all(|v| v.is_empty()) {
510510
return;
511511
}
512+
512513
let tcx = self.tcx();
513514
// FIXME: Marked `mut` so that we can replace the spans further below with a more
514515
// appropriate one, but this should be handled earlier in the span assignment.
@@ -581,6 +582,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
581582
}
582583
}
583584

585+
// We get all the associated items that _are_ set,
586+
// so that we can check if any of their names match one of the ones we are missing.
587+
// This would mean that they are shadowing the associated type we are missing,
588+
// and we can then use their span to indicate this to the user.
589+
let bound_names = trait_bounds
590+
.iter()
591+
.filter_map(|poly_trait_ref| {
592+
let path = poly_trait_ref.trait_ref.path.segments.last()?;
593+
let args = path.args?;
594+
595+
Some(args.bindings.iter().filter_map(|binding| {
596+
let ident = binding.ident;
597+
let trait_def = path.res.def_id();
598+
let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind(
599+
tcx,
600+
ident,
601+
AssocKind::Type,
602+
trait_def,
603+
);
604+
605+
Some((ident.name, assoc_item?))
606+
}))
607+
})
608+
.flatten()
609+
.collect::<FxHashMap<Symbol, &AssocItem>>();
610+
584611
let mut names = names
585612
.into_iter()
586613
.map(|(trait_, mut assocs)| {
@@ -621,25 +648,51 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
621648
*names.entry(item.name).or_insert(0) += 1;
622649
}
623650
let mut dupes = false;
651+
let mut shadows = false;
624652
for item in assoc_items {
625653
let prefix = if names[&item.name] > 1 {
626654
let trait_def_id = item.container_id(tcx);
627655
dupes = true;
628656
format!("{}::", tcx.def_path_str(trait_def_id))
657+
} else if bound_names.get(&item.name).is_some_and(|x| x != &item) {
658+
let trait_def_id = item.container_id(tcx);
659+
shadows = true;
660+
format!("{}::", tcx.def_path_str(trait_def_id))
629661
} else {
630662
String::new()
631663
};
664+
665+
let mut is_shadowed = false;
666+
667+
if let Some(assoc_item) = bound_names.get(&item.name)
668+
&& assoc_item != &item
669+
{
670+
is_shadowed = true;
671+
672+
let is_local = tcx.hir().get_if_local(assoc_item.def_id).is_some();
673+
let rename_message = if is_local { ", consider renaming it" } else { "" };
674+
err.span_label(
675+
tcx.def_span(assoc_item.def_id),
676+
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
677+
);
678+
}
679+
680+
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
681+
632682
if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
633-
err.span_label(sp, format!("`{}{}` defined here", prefix, item.name));
683+
err.span_label(
684+
sp,
685+
format!("`{}{}` defined here{}", prefix, item.name, rename_message),
686+
);
634687
}
635688
}
636689
if potential_assoc_types.len() == assoc_items.len() {
637690
// When the amount of missing associated types equals the number of
638691
// extra type arguments present. A suggesting to replace the generic args with
639692
// associated types is already emitted.
640693
already_has_generics_args_suggestion = true;
641-
} else if let (Ok(snippet), false) =
642-
(tcx.sess.source_map().span_to_snippet(*span), dupes)
694+
} else if let (Ok(snippet), false, false) =
695+
(tcx.sess.source_map().span_to_snippet(*span), dupes, shadows)
643696
{
644697
let types: Vec<_> =
645698
assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect();
@@ -721,6 +774,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
721774
err.span_help(where_constraints, where_msg);
722775
}
723776
}
777+
724778
err.emit();
725779
}
726780
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Test that no help message is emitted that suggests renaming the
2+
// associated type from a non-local trait
3+
4+
pub trait NewIter: Iterator {
5+
type Item;
6+
}
7+
8+
impl<T> Clone for Box<dyn NewIter<Item = T>> {
9+
//~^ ERROR the value of the associated type `Item` in `Iterator` must be specified
10+
fn clone(&self) -> Self {
11+
unimplemented!();
12+
}
13+
}
14+
15+
pub fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0191]: the value of the associated type `Item` in `Iterator` must be specified
2+
--> $DIR/associated-type-shadowed-from-non-local-supertrait.rs:8:27
3+
|
4+
LL | type Item;
5+
| --------- `Iterator::Item` shadowed here, consider renaming it
6+
...
7+
LL | impl<T> Clone for Box<dyn NewIter<Item = T>> {
8+
| ^^^^^^^^^^^^^^^^^ associated type `Item` must be specified
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0191`.
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;
10+
}
11+
12+
impl<T> Clone for Box<dyn Sub<X = T>> {
13+
//~^ ERROR value of the associated type `X` in `Super` must be specified
14+
fn clone(&self) -> Self {
15+
unimplemented!();
16+
}
17+
}
18+
19+
pub fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0191]: the value of the associated type `X` in `Super` must be specified
2+
--> $DIR/associated-type-shadowed-from-supertrait.rs:12:27
3+
|
4+
LL | type X;
5+
| ------ `Super::X` defined here, consider renaming it
6+
...
7+
LL | type X;
8+
| ------ `Super::X` shadowed here, consider renaming it
9+
...
10+
LL | impl<T> Clone for Box<dyn Sub<X = T>> {
11+
| ^^^^^^^^^^ associated type `X` must be specified
12+
13+
error: aborting due to 1 previous error
14+
15+
For more information about this error, try `rustc --explain E0191`.

0 commit comments

Comments
 (0)