Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5bef8ce

Browse files
committedDec 3, 2024
Dont use span as key when collecting missing associated types from dyn
1 parent c44b3d5 commit 5bef8ce

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.projection_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.projection_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
@@ -716,51 +716,40 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
716716
/// emit a generic note suggesting using a `where` clause to constraint instead.
717717
pub(crate) fn check_for_required_assoc_tys(
718718
&self,
719-
associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
719+
principal_span: Span,
720+
missing_assoc_types: FxIndexSet<DefId>,
720721
potential_assoc_types: Vec<usize>,
721722
trait_bounds: &[hir::PolyTraitRef<'_>],
722723
) -> Result<(), ErrorGuaranteed> {
723-
if associated_types.values().all(|v| v.is_empty()) {
724+
if missing_assoc_types.is_empty() {
724725
return Ok(());
725726
}
726727

727728
let tcx = self.tcx();
728-
// FIXME: Marked `mut` so that we can replace the spans further below with a more
729-
// appropriate one, but this should be handled earlier in the span assignment.
730-
let associated_types: FxIndexMap<Span, Vec<_>> = associated_types
731-
.into_iter()
732-
.map(|(span, def_ids)| {
733-
(span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
734-
})
735-
.collect();
729+
let missing_assoc_types: Vec<_> =
730+
missing_assoc_types.into_iter().map(|def_id| tcx.associated_item(def_id)).collect();
736731
let mut names: FxIndexMap<String, Vec<Symbol>> = Default::default();
737732
let mut names_len = 0;
738733

739734
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
740735
// `issue-22560.rs`.
741-
let mut trait_bound_spans: Vec<Span> = vec![];
742736
let mut dyn_compatibility_violations = Ok(());
743-
for (span, items) in &associated_types {
744-
if !items.is_empty() {
745-
trait_bound_spans.push(*span);
746-
}
747-
for assoc_item in items {
748-
let trait_def_id = assoc_item.container_id(tcx);
749-
names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
750-
names_len += 1;
751-
752-
let violations =
753-
dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
754-
if !violations.is_empty() {
755-
dyn_compatibility_violations = Err(report_dyn_incompatibility(
756-
tcx,
757-
*span,
758-
None,
759-
trait_def_id,
760-
&violations,
761-
)
762-
.emit());
763-
}
737+
for assoc_item in &missing_assoc_types {
738+
let trait_def_id = assoc_item.container_id(tcx);
739+
names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
740+
names_len += 1;
741+
742+
let violations =
743+
dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
744+
if !violations.is_empty() {
745+
dyn_compatibility_violations = Err(report_dyn_incompatibility(
746+
tcx,
747+
principal_span,
748+
None,
749+
trait_def_id,
750+
&violations,
751+
)
752+
.emit());
764753
}
765754
}
766755

@@ -821,10 +810,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
821810
names.sort();
822811
let names = names.join(", ");
823812

824-
trait_bound_spans.sort();
825813
let mut err = struct_span_code_err!(
826814
self.dcx(),
827-
trait_bound_spans,
815+
principal_span,
828816
E0191,
829817
"the value of the associated type{} {} must be specified",
830818
pluralize!(names_len),
@@ -834,81 +822,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
834822
let mut types_count = 0;
835823
let mut where_constraints = vec![];
836824
let mut already_has_generics_args_suggestion = false;
837-
for (span, assoc_items) in &associated_types {
838-
let mut names: UnordMap<_, usize> = Default::default();
839-
for item in assoc_items {
840-
types_count += 1;
841-
*names.entry(item.name).or_insert(0) += 1;
842-
}
843-
let mut dupes = false;
844-
let mut shadows = false;
845-
for item in assoc_items {
846-
let prefix = if names[&item.name] > 1 {
847-
let trait_def_id = item.container_id(tcx);
848-
dupes = true;
849-
format!("{}::", tcx.def_path_str(trait_def_id))
850-
} else if bound_names.get(&item.name).is_some_and(|x| x != &item) {
851-
let trait_def_id = item.container_id(tcx);
852-
shadows = true;
853-
format!("{}::", tcx.def_path_str(trait_def_id))
854-
} else {
855-
String::new()
856-
};
857825

858-
let mut is_shadowed = false;
859-
860-
if let Some(assoc_item) = bound_names.get(&item.name)
861-
&& assoc_item != &item
862-
{
863-
is_shadowed = true;
826+
let mut names: UnordMap<_, usize> = Default::default();
827+
for item in &missing_assoc_types {
828+
types_count += 1;
829+
*names.entry(item.name).or_insert(0) += 1;
830+
}
831+
let mut dupes = false;
832+
let mut shadows = false;
833+
for item in &missing_assoc_types {
834+
let prefix = if names[&item.name] > 1 {
835+
let trait_def_id = item.container_id(tcx);
836+
dupes = true;
837+
format!("{}::", tcx.def_path_str(trait_def_id))
838+
} else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
839+
let trait_def_id = item.container_id(tcx);
840+
shadows = true;
841+
format!("{}::", tcx.def_path_str(trait_def_id))
842+
} else {
843+
String::new()
844+
};
864845

865-
let rename_message =
866-
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
867-
err.span_label(
868-
tcx.def_span(assoc_item.def_id),
869-
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
870-
);
871-
}
846+
let mut is_shadowed = false;
872847

873-
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
848+
if let Some(assoc_item) = bound_names.get(&item.name)
849+
&& *assoc_item != item
850+
{
851+
is_shadowed = true;
874852

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

0 commit comments

Comments
 (0)
Failed to load comments.