Skip to content

Commit 70be327

Browse files
Rollup merge of #81279 - bugadani:iter, r=davidtwco
Small refactor in typeck - `check_impl_items_against_trait` only queries and walks through associated items once - extracted function that reports errors - don't check specialization validity when trait item does not match - small additional cleanups
2 parents 504d6de + f29b329 commit 70be327

File tree

1 file changed

+129
-113
lines changed

1 file changed

+129
-113
lines changed

compiler/rustc_typeck/src/check/check.rs

+129-113
Original file line numberDiff line numberDiff line change
@@ -846,21 +846,13 @@ pub(super) fn check_specialization_validity<'tcx>(
846846
Ok(ancestors) => ancestors,
847847
Err(_) => return,
848848
};
849-
let mut ancestor_impls = ancestors
850-
.skip(1)
851-
.filter_map(|parent| {
852-
if parent.is_from_trait() {
853-
None
854-
} else {
855-
Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
856-
}
857-
})
858-
.peekable();
859-
860-
if ancestor_impls.peek().is_none() {
861-
// No parent, nothing to specialize.
862-
return;
863-
}
849+
let mut ancestor_impls = ancestors.skip(1).filter_map(|parent| {
850+
if parent.is_from_trait() {
851+
None
852+
} else {
853+
Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
854+
}
855+
});
864856

865857
let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
866858
match parent_item {
@@ -902,8 +894,6 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
902894
impl_trait_ref: ty::TraitRef<'tcx>,
903895
impl_item_refs: &[hir::ImplItemRef<'_>],
904896
) {
905-
let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
906-
907897
// If the trait reference itself is erroneous (so the compilation is going
908898
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
909899
// isn't populated for such impls.
@@ -931,111 +921,75 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
931921

932922
// Locate trait definition and items
933923
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
934-
935-
let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
924+
let impl_items = impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
925+
let associated_items = tcx.associated_items(impl_trait_ref.def_id);
936926

937927
// Check existing impl methods to see if they are both present in trait
938928
// and compatible with trait signature
939-
for impl_item in impl_items() {
940-
let namespace = impl_item.kind.namespace();
929+
for impl_item in impl_items {
941930
let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id));
942-
let ty_trait_item = tcx
943-
.associated_items(impl_trait_ref.def_id)
944-
.find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id)
945-
.or_else(|| {
946-
// Not compatible, but needed for the error message
947-
tcx.associated_items(impl_trait_ref.def_id)
948-
.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id)
949-
.next()
950-
});
951-
952-
// Check that impl definition matches trait definition
953-
if let Some(ty_trait_item) = ty_trait_item {
931+
932+
let mut items =
933+
associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id);
934+
935+
let (compatible_kind, ty_trait_item) = if let Some(ty_trait_item) = items.next() {
936+
let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
937+
(ty::AssocKind::Const, hir::ImplItemKind::Const(..)) => true,
938+
(ty::AssocKind::Fn, hir::ImplItemKind::Fn(..)) => true,
939+
(ty::AssocKind::Type, hir::ImplItemKind::TyAlias(..)) => true,
940+
_ => false,
941+
};
942+
943+
// If we don't have a compatible item, we'll use the first one whose name matches
944+
// to report an error.
945+
let mut compatible_kind = is_compatible(&ty_trait_item);
946+
let mut trait_item = ty_trait_item;
947+
948+
if !compatible_kind {
949+
if let Some(ty_trait_item) = items.find(is_compatible) {
950+
compatible_kind = true;
951+
trait_item = ty_trait_item;
952+
}
953+
}
954+
955+
(compatible_kind, trait_item)
956+
} else {
957+
continue;
958+
};
959+
960+
if compatible_kind {
954961
match impl_item.kind {
955962
hir::ImplItemKind::Const(..) => {
956963
// Find associated const definition.
957-
if ty_trait_item.kind == ty::AssocKind::Const {
958-
compare_const_impl(
959-
tcx,
960-
&ty_impl_item,
961-
impl_item.span,
962-
&ty_trait_item,
963-
impl_trait_ref,
964-
);
965-
} else {
966-
let mut err = struct_span_err!(
967-
tcx.sess,
968-
impl_item.span,
969-
E0323,
970-
"item `{}` is an associated const, \
971-
which doesn't match its trait `{}`",
972-
ty_impl_item.ident,
973-
impl_trait_ref.print_only_trait_path()
974-
);
975-
err.span_label(impl_item.span, "does not match trait");
976-
// We can only get the spans from local trait definition
977-
// Same for E0324 and E0325
978-
if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) {
979-
err.span_label(trait_span, "item in trait");
980-
}
981-
err.emit()
982-
}
964+
compare_const_impl(
965+
tcx,
966+
&ty_impl_item,
967+
impl_item.span,
968+
&ty_trait_item,
969+
impl_trait_ref,
970+
);
983971
}
984972
hir::ImplItemKind::Fn(..) => {
985973
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
986-
if ty_trait_item.kind == ty::AssocKind::Fn {
987-
compare_impl_method(
988-
tcx,
989-
&ty_impl_item,
990-
impl_item.span,
991-
&ty_trait_item,
992-
impl_trait_ref,
993-
opt_trait_span,
994-
);
995-
} else {
996-
let mut err = struct_span_err!(
997-
tcx.sess,
998-
impl_item.span,
999-
E0324,
1000-
"item `{}` is an associated method, \
1001-
which doesn't match its trait `{}`",
1002-
ty_impl_item.ident,
1003-
impl_trait_ref.print_only_trait_path()
1004-
);
1005-
err.span_label(impl_item.span, "does not match trait");
1006-
if let Some(trait_span) = opt_trait_span {
1007-
err.span_label(trait_span, "item in trait");
1008-
}
1009-
err.emit()
1010-
}
974+
compare_impl_method(
975+
tcx,
976+
&ty_impl_item,
977+
impl_item.span,
978+
&ty_trait_item,
979+
impl_trait_ref,
980+
opt_trait_span,
981+
);
1011982
}
1012983
hir::ImplItemKind::TyAlias(_) => {
1013984
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
1014-
if ty_trait_item.kind == ty::AssocKind::Type {
1015-
compare_ty_impl(
1016-
tcx,
1017-
&ty_impl_item,
1018-
impl_item.span,
1019-
&ty_trait_item,
1020-
impl_trait_ref,
1021-
opt_trait_span,
1022-
);
1023-
} else {
1024-
let mut err = struct_span_err!(
1025-
tcx.sess,
1026-
impl_item.span,
1027-
E0325,
1028-
"item `{}` is an associated type, \
1029-
which doesn't match its trait `{}`",
1030-
ty_impl_item.ident,
1031-
impl_trait_ref.print_only_trait_path()
1032-
);
1033-
err.span_label(impl_item.span, "does not match trait");
1034-
if let Some(trait_span) = opt_trait_span {
1035-
err.span_label(trait_span, "item in trait");
1036-
}
1037-
err.emit()
1038-
}
985+
compare_ty_impl(
986+
tcx,
987+
&ty_impl_item,
988+
impl_item.span,
989+
&ty_trait_item,
990+
impl_trait_ref,
991+
opt_trait_span,
992+
);
1039993
}
1040994
}
1041995

@@ -1046,12 +1000,22 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
10461000
impl_id.to_def_id(),
10471001
impl_item,
10481002
);
1003+
} else {
1004+
report_mismatch_error(
1005+
tcx,
1006+
ty_trait_item.def_id,
1007+
impl_trait_ref,
1008+
impl_item,
1009+
&ty_impl_item,
1010+
);
10491011
}
10501012
}
10511013

1052-
// Check for missing items from trait
1053-
let mut missing_items = Vec::new();
10541014
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
1015+
let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
1016+
1017+
// Check for missing items from trait
1018+
let mut missing_items = Vec::new();
10551019
for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
10561020
let is_implemented = ancestors
10571021
.leaf_def(tcx, trait_item.ident, trait_item.kind)
@@ -1064,11 +1028,63 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
10641028
}
10651029
}
10661030
}
1031+
1032+
if !missing_items.is_empty() {
1033+
missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
1034+
}
10671035
}
1036+
}
1037+
1038+
#[inline(never)]
1039+
#[cold]
1040+
fn report_mismatch_error<'tcx>(
1041+
tcx: TyCtxt<'tcx>,
1042+
trait_item_def_id: DefId,
1043+
impl_trait_ref: ty::TraitRef<'tcx>,
1044+
impl_item: &hir::ImplItem<'_>,
1045+
ty_impl_item: &ty::AssocItem,
1046+
) {
1047+
let mut err = match impl_item.kind {
1048+
hir::ImplItemKind::Const(..) => {
1049+
// Find associated const definition.
1050+
struct_span_err!(
1051+
tcx.sess,
1052+
impl_item.span,
1053+
E0323,
1054+
"item `{}` is an associated const, which doesn't match its trait `{}`",
1055+
ty_impl_item.ident,
1056+
impl_trait_ref.print_only_trait_path()
1057+
)
1058+
}
1059+
1060+
hir::ImplItemKind::Fn(..) => {
1061+
struct_span_err!(
1062+
tcx.sess,
1063+
impl_item.span,
1064+
E0324,
1065+
"item `{}` is an associated method, which doesn't match its trait `{}`",
1066+
ty_impl_item.ident,
1067+
impl_trait_ref.print_only_trait_path()
1068+
)
1069+
}
10681070

1069-
if !missing_items.is_empty() {
1070-
missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
1071+
hir::ImplItemKind::TyAlias(_) => {
1072+
struct_span_err!(
1073+
tcx.sess,
1074+
impl_item.span,
1075+
E0325,
1076+
"item `{}` is an associated type, which doesn't match its trait `{}`",
1077+
ty_impl_item.ident,
1078+
impl_trait_ref.print_only_trait_path()
1079+
)
1080+
}
1081+
};
1082+
1083+
err.span_label(impl_item.span, "does not match trait");
1084+
if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
1085+
err.span_label(trait_span, "item in trait");
10711086
}
1087+
err.emit();
10721088
}
10731089

10741090
/// Checks whether a type can be represented in memory. In particular, it

0 commit comments

Comments
 (0)