Skip to content

Commit 25a7fdf

Browse files
Dont use span as key when collecting missing associated types from dyn
1 parent 1f3bf23 commit 25a7fdf

File tree

2 files changed

+134
-149
lines changed

2 files changed

+134
-149
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs

+20-21
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
1+
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
22
use rustc_errors::codes::*;
33
use rustc_errors::struct_span_code_err;
44
use rustc_hir as hir;
55
use rustc_hir::def::{DefKind, Res};
6-
use rustc_hir::def_id::DefId;
76
use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
87
use rustc_middle::span_bug;
98
use rustc_middle::ty::fold::BottomUpFolder;
109
use rustc_middle::ty::{
1110
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
1211
TypeVisitableExt, Upcast,
1312
};
14-
use rustc_span::{ErrorGuaranteed, Span};
13+
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
1514
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
1615
use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
1716
use rustc_type_ir::elaborate::ClauseWithSupertraitSpan;
@@ -128,8 +127,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
128127
}
129128
}
130129

131-
let mut associated_types: FxIndexMap<Span, FxIndexSet<DefId>> = FxIndexMap::default();
130+
let mut needed_associated_types = FxIndexSet::default();
132131

132+
let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1);
133133
let regular_traits_refs_spans = trait_bounds
134134
.into_iter()
135135
.filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
@@ -146,11 +146,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
146146
match bound_predicate.skip_binder() {
147147
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
148148
let pred = bound_predicate.rebind(pred);
149-
associated_types.entry(original_span).or_default().extend(
149+
needed_associated_types.extend(
150150
tcx.associated_items(pred.def_id())
151151
.in_definition_order()
152152
.filter(|item| item.kind == ty::AssocKind::Type)
153153
.filter(|item| !item.is_impl_trait_in_trait())
154+
// If the associated type has a `where Self: Sized` bound,
155+
// we do not need to constrain the associated type.
156+
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
154157
.map(|item| item.def_id),
155158
);
156159
}
@@ -201,26 +204,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
201204
// So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
202205
// types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
203206
// corresponding `Projection` clause
204-
for def_ids in associated_types.values_mut() {
205-
for (projection_bound, span) in &projection_bounds {
206-
let def_id = projection_bound.item_def_id();
207-
def_ids.swap_remove(&def_id);
208-
if tcx.generics_require_sized_self(def_id) {
209-
tcx.emit_node_span_lint(
210-
UNUSED_ASSOCIATED_TYPE_BOUNDS,
211-
hir_id,
212-
*span,
213-
crate::errors::UnusedAssociatedTypeBounds { span: *span },
214-
);
215-
}
207+
for (projection_bound, span) in &projection_bounds {
208+
let def_id = projection_bound.item_def_id();
209+
needed_associated_types.swap_remove(&def_id);
210+
if tcx.generics_require_sized_self(def_id) {
211+
tcx.emit_node_span_lint(
212+
UNUSED_ASSOCIATED_TYPE_BOUNDS,
213+
hir_id,
214+
*span,
215+
crate::errors::UnusedAssociatedTypeBounds { span: *span },
216+
);
216217
}
217-
// If the associated type has a `where Self: Sized` bound, we do not need to constrain the associated
218-
// type in the `dyn Trait`.
219-
def_ids.retain(|def_id| !tcx.generics_require_sized_self(def_id));
220218
}
221219

222220
if let Err(guar) = self.check_for_required_assoc_tys(
223-
associated_types,
221+
principal_span,
222+
needed_associated_types,
224223
potential_assoc_types,
225224
hir_trait_bounds,
226225
) {

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

+114-128
Original file line numberDiff line numberDiff line change
@@ -722,51 +722,40 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
722722
/// emit a generic note suggesting using a `where` clause to constraint instead.
723723
pub(crate) fn check_for_required_assoc_tys(
724724
&self,
725-
associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
725+
principal_span: Span,
726+
missing_assoc_types: FxIndexSet<DefId>,
726727
potential_assoc_types: Vec<usize>,
727728
trait_bounds: &[hir::PolyTraitRef<'_>],
728729
) -> Result<(), ErrorGuaranteed> {
729-
if associated_types.values().all(|v| v.is_empty()) {
730+
if missing_assoc_types.is_empty() {
730731
return Ok(());
731732
}
732733

733734
let tcx = self.tcx();
734-
// FIXME: Marked `mut` so that we can replace the spans further below with a more
735-
// appropriate one, but this should be handled earlier in the span assignment.
736-
let associated_types: FxIndexMap<Span, Vec<_>> = associated_types
737-
.into_iter()
738-
.map(|(span, def_ids)| {
739-
(span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
740-
})
741-
.collect();
735+
let missing_assoc_types: Vec<_> =
736+
missing_assoc_types.into_iter().map(|def_id| tcx.associated_item(def_id)).collect();
742737
let mut names: FxIndexMap<String, Vec<Symbol>> = Default::default();
743738
let mut names_len = 0;
744739

745740
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
746741
// `issue-22560.rs`.
747-
let mut trait_bound_spans: Vec<Span> = vec![];
748742
let mut dyn_compatibility_violations = Ok(());
749-
for (span, items) in &associated_types {
750-
if !items.is_empty() {
751-
trait_bound_spans.push(*span);
752-
}
753-
for assoc_item in items {
754-
let trait_def_id = assoc_item.container_id(tcx);
755-
names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
756-
names_len += 1;
757-
758-
let violations =
759-
dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
760-
if !violations.is_empty() {
761-
dyn_compatibility_violations = Err(report_dyn_incompatibility(
762-
tcx,
763-
*span,
764-
None,
765-
trait_def_id,
766-
&violations,
767-
)
768-
.emit());
769-
}
743+
for assoc_item in &missing_assoc_types {
744+
let trait_def_id = assoc_item.container_id(tcx);
745+
names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
746+
names_len += 1;
747+
748+
let violations =
749+
dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
750+
if !violations.is_empty() {
751+
dyn_compatibility_violations = Err(report_dyn_incompatibility(
752+
tcx,
753+
principal_span,
754+
None,
755+
trait_def_id,
756+
&violations,
757+
)
758+
.emit());
770759
}
771760
}
772761

@@ -827,10 +816,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
827816
names.sort();
828817
let names = names.join(", ");
829818

830-
trait_bound_spans.sort();
831819
let mut err = struct_span_code_err!(
832820
self.dcx(),
833-
trait_bound_spans,
821+
principal_span,
834822
E0191,
835823
"the value of the associated type{} {} must be specified",
836824
pluralize!(names_len),
@@ -840,81 +828,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
840828
let mut types_count = 0;
841829
let mut where_constraints = vec![];
842830
let mut already_has_generics_args_suggestion = false;
843-
for (span, assoc_items) in &associated_types {
844-
let mut names: UnordMap<_, usize> = Default::default();
845-
for item in assoc_items {
846-
types_count += 1;
847-
*names.entry(item.name).or_insert(0) += 1;
848-
}
849-
let mut dupes = false;
850-
let mut shadows = false;
851-
for item in assoc_items {
852-
let prefix = if names[&item.name] > 1 {
853-
let trait_def_id = item.container_id(tcx);
854-
dupes = true;
855-
format!("{}::", tcx.def_path_str(trait_def_id))
856-
} else if bound_names.get(&item.name).is_some_and(|x| x != &item) {
857-
let trait_def_id = item.container_id(tcx);
858-
shadows = true;
859-
format!("{}::", tcx.def_path_str(trait_def_id))
860-
} else {
861-
String::new()
862-
};
863831

864-
let mut is_shadowed = false;
865-
866-
if let Some(assoc_item) = bound_names.get(&item.name)
867-
&& assoc_item != &item
868-
{
869-
is_shadowed = true;
832+
let mut names: UnordMap<_, usize> = Default::default();
833+
for item in &missing_assoc_types {
834+
types_count += 1;
835+
*names.entry(item.name).or_insert(0) += 1;
836+
}
837+
let mut dupes = false;
838+
let mut shadows = false;
839+
for item in &missing_assoc_types {
840+
let prefix = if names[&item.name] > 1 {
841+
let trait_def_id = item.container_id(tcx);
842+
dupes = true;
843+
format!("{}::", tcx.def_path_str(trait_def_id))
844+
} else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
845+
let trait_def_id = item.container_id(tcx);
846+
shadows = true;
847+
format!("{}::", tcx.def_path_str(trait_def_id))
848+
} else {
849+
String::new()
850+
};
870851

871-
let rename_message =
872-
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
873-
err.span_label(
874-
tcx.def_span(assoc_item.def_id),
875-
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
876-
);
877-
}
852+
let mut is_shadowed = false;
878853

879-
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
854+
if let Some(assoc_item) = bound_names.get(&item.name)
855+
&& *assoc_item != item
856+
{
857+
is_shadowed = true;
880858

881-
if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
882-
err.span_label(
883-
sp,
884-
format!("`{}{}` defined here{}", prefix, item.name, rename_message),
885-
);
886-
}
859+
let rename_message =
860+
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
861+
err.span_label(
862+
tcx.def_span(assoc_item.def_id),
863+
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
864+
);
887865
}
888-
if potential_assoc_types.len() == assoc_items.len() {
889-
// When the amount of missing associated types equals the number of
890-
// extra type arguments present. A suggesting to replace the generic args with
891-
// associated types is already emitted.
892-
already_has_generics_args_suggestion = true;
893-
} else if let (Ok(snippet), false, false) =
894-
(tcx.sess.source_map().span_to_snippet(*span), dupes, shadows)
895-
{
896-
let types: Vec<_> =
897-
assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect();
898-
let code = if snippet.ends_with('>') {
899-
// The user wrote `Trait<'a>` or similar and we don't have a type we can
900-
// suggest, but at least we can clue them to the correct syntax
901-
// `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
902-
// suggestion.
903-
format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
904-
} else if in_expr_or_pat {
905-
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
906-
// least we can clue them to the correct syntax `Iterator::<Item = Type>`.
907-
format!("{}::<{}>", snippet, types.join(", "))
908-
} else {
909-
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
910-
// least we can clue them to the correct syntax `Iterator<Item = Type>`.
911-
format!("{}<{}>", snippet, types.join(", "))
912-
};
913-
suggestions.push((*span, code));
914-
} else if dupes {
915-
where_constraints.push(*span);
866+
867+
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
868+
869+
if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
870+
err.span_label(
871+
sp,
872+
format!("`{}{}` defined here{}", prefix, item.name, rename_message),
873+
);
916874
}
917875
}
876+
if potential_assoc_types.len() == missing_assoc_types.len() {
877+
// When the amount of missing associated types equals the number of
878+
// extra type arguments present. A suggesting to replace the generic args with
879+
// associated types is already emitted.
880+
already_has_generics_args_suggestion = true;
881+
} else if let (Ok(snippet), false, false) =
882+
(tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
883+
{
884+
let types: Vec<_> =
885+
missing_assoc_types.iter().map(|item| format!("{} = Type", item.name)).collect();
886+
let code = if snippet.ends_with('>') {
887+
// The user wrote `Trait<'a>` or similar and we don't have a type we can
888+
// suggest, but at least we can clue them to the correct syntax
889+
// `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
890+
// suggestion.
891+
format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
892+
} else if in_expr_or_pat {
893+
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
894+
// least we can clue them to the correct syntax `Iterator::<Item = Type>`.
895+
format!("{}::<{}>", snippet, types.join(", "))
896+
} else {
897+
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
898+
// least we can clue them to the correct syntax `Iterator<Item = Type>`.
899+
format!("{}<{}>", snippet, types.join(", "))
900+
};
901+
suggestions.push((principal_span, code));
902+
} else if dupes {
903+
where_constraints.push(principal_span);
904+
}
905+
918906
let where_msg = "consider introducing a new type parameter, adding `where` constraints \
919907
using the fully-qualified path to the associated types";
920908
if !where_constraints.is_empty() && suggestions.is_empty() {
@@ -925,32 +913,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
925913
}
926914
if suggestions.len() != 1 || already_has_generics_args_suggestion {
927915
// We don't need this label if there's an inline suggestion, show otherwise.
928-
for (span, assoc_items) in &associated_types {
929-
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
930-
for item in assoc_items {
931-
types_count += 1;
932-
*names.entry(item.name).or_insert(0) += 1;
933-
}
934-
let mut label = vec![];
935-
for item in assoc_items {
936-
let postfix = if names[&item.name] > 1 {
937-
let trait_def_id = item.container_id(tcx);
938-
format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
939-
} else {
940-
String::new()
941-
};
942-
label.push(format!("`{}`{}", item.name, postfix));
943-
}
944-
if !label.is_empty() {
945-
err.span_label(
946-
*span,
947-
format!(
948-
"associated type{} {} must be specified",
949-
pluralize!(label.len()),
950-
label.join(", "),
951-
),
952-
);
953-
}
916+
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
917+
for item in &missing_assoc_types {
918+
types_count += 1;
919+
*names.entry(item.name).or_insert(0) += 1;
920+
}
921+
let mut label = vec![];
922+
for item in &missing_assoc_types {
923+
let postfix = if names[&item.name] > 1 {
924+
let trait_def_id = item.container_id(tcx);
925+
format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
926+
} else {
927+
String::new()
928+
};
929+
label.push(format!("`{}`{}", item.name, postfix));
930+
}
931+
if !label.is_empty() {
932+
err.span_label(
933+
principal_span,
934+
format!(
935+
"associated type{} {} must be specified",
936+
pluralize!(label.len()),
937+
label.join(", "),
938+
),
939+
);
954940
}
955941
}
956942
suggestions.sort_by_key(|&(span, _)| span);

0 commit comments

Comments
 (0)