Skip to content

Commit dd6126e

Browse files
committed
Auto merge of #117661 - TheLazyDutchman:point_out_shadowed_associated_types, r=petrochenkov
Added shadowed hint for overlapping associated types Previously, when you tried to set an associated type that is shadowed by an associated type in a subtrait, like this: ```rust trait A { type X; } trait B: A { type X; // note: this is legal } impl<Y> Clone for Box<dyn B<X=Y, X=Y>> { fn clone(&self) -> Self { todo!() } } you got a confusing error message, that says nothing about the shadowing: error[E0719]: the value of the associated type `X` (from trait `B`) is already specified --> test.rs:9:34 | 9 | impl<Y> Clone for Box<dyn B<X=Y, X=Y>> { | --- ^^^ re-bound here | | | `X` bound here first error[E0191]: the value of the associated type `X` (from trait `A`) must be specified --> test.rs:9:27 | 2 | type X; | ------ `X` defined here ... 9 | impl<Y> Clone for Box<dyn B<X=Y, X=Y>> { | ^^^^^^^^^^^ help: specify the associated type: `B<X=Y, X=Y, X = Type>` error: aborting due to 2 previous errors Some errors have detailed explanations: E0191, E0719. For more information about an error, try `rustc --explain E0191`. ``` Now instead, the error shows that the associated type is shadowed, and suggests renaming as a potential fix. ```rust error[E0719]: the value of the associated type `X` in trait `B` is already specified --> test.rs:9:34 | 9 | impl<Y> Clone for Box<dyn B<X=Y, X=Y>> { | --- ^^^ re-bound here | | | `X` bound here first error[E0191]: the value of the associated type `X` in `A` must be specified --> test.rs:9:27 | 2 | type X; | ------ `A::X` defined here ... 6 | type X; // note: this is legal | ------ `A::X` shadowed here ... 9 | impl<Y> Clone for Box<dyn B<X=Y, X=Y>> { | ^^^^^^^^^^^ associated type `X` must be specified | help: consider renaming this associated type --> test.rs:2:5 | 2 | type X; | ^^^^^^ help: consider renaming this associated type --> test.rs:6:5 | 6 | type X; // note: this is legal | ^^^^^^ ``` error: aborting due to 2 previous errors Some errors have detailed explanations: E0191, E0719. For more information about an error, try `rustc --explain E0191`. The rename help message is only emitted when the trait is local. This is true both for the supertrait as for the subtrait. There might be cases where you can use the fully qualified path (for instance, in a where clause), but this PR currently does not deal with that. fixes #100109 (continues from #117642, because I didn't know renaming the branch would close the PR)
2 parents 15bb3e2 + 3234418 commit dd6126e

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 rename_message =
673+
if assoc_item.def_id.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)