Skip to content

Commit d63b278

Browse files
committed
Only scan through assoc items once in check_impl_items_against_trait
1 parent 9988821 commit d63b278

File tree

1 file changed

+117
-98
lines changed

1 file changed

+117
-98
lines changed

compiler/rustc_typeck/src/check/check.rs

Lines changed: 117 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -846,15 +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-
});
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+
});
858856

859857
let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
860858
match parent_item {
@@ -931,105 +929,72 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
931929
// Check existing impl methods to see if they are both present in trait
932930
// and compatible with trait signature
933931
for impl_item in impl_items {
934-
let namespace = impl_item.kind.namespace();
935932
let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id));
936-
let ty_trait_item = tcx
937-
.associated_items(impl_trait_ref.def_id)
938-
.find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id)
939-
.or_else(|| {
940-
// Not compatible, but needed for the error message
941-
tcx.associated_items(impl_trait_ref.def_id)
942-
.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id)
943-
.next()
944-
});
945-
946-
// Check that impl definition matches trait definition
947-
if let Some(ty_trait_item) = ty_trait_item {
933+
let associated_items = tcx.associated_items(impl_trait_ref.def_id);
934+
935+
let mut items = associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id);
936+
937+
let (compatible_kind, ty_trait_item) = if let Some(ty_trait_item) = items.next() {
938+
939+
let is_compatible = |ty: &&ty::AssocItem| {
940+
match (ty.kind, &impl_item.kind) {
941+
(ty::AssocKind::Const, hir::ImplItemKind::Const(..)) => true,
942+
(ty::AssocKind::Fn, hir::ImplItemKind::Fn(..)) => true,
943+
(ty::AssocKind::Type, hir::ImplItemKind::TyAlias(..)) => true,
944+
_ => false
945+
}
946+
};
947+
948+
// If we don't have a compatible item, we'll use the first one whose name matches
949+
// to report an error.
950+
let mut compatible_kind = is_compatible(&ty_trait_item);
951+
let mut trait_item = ty_trait_item;
952+
953+
if !compatible_kind {
954+
if let Some(ty_trait_item) = items.find(is_compatible) {
955+
compatible_kind = true;
956+
trait_item = ty_trait_item;
957+
}
958+
}
959+
960+
(compatible_kind, trait_item)
961+
} else {
962+
continue;
963+
};
964+
965+
if compatible_kind {
948966
match impl_item.kind {
949967
hir::ImplItemKind::Const(..) => {
950968
// Find associated const definition.
951-
if ty_trait_item.kind == ty::AssocKind::Const {
952-
compare_const_impl(
953-
tcx,
954-
&ty_impl_item,
955-
impl_item.span,
956-
&ty_trait_item,
957-
impl_trait_ref,
958-
);
959-
} else {
960-
let mut err = struct_span_err!(
961-
tcx.sess,
962-
impl_item.span,
963-
E0323,
964-
"item `{}` is an associated const, \
965-
which doesn't match its trait `{}`",
966-
ty_impl_item.ident,
967-
impl_trait_ref.print_only_trait_path()
968-
);
969-
err.span_label(impl_item.span, "does not match trait");
970-
// We can only get the spans from local trait definition
971-
// Same for E0324 and E0325
972-
if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) {
973-
err.span_label(trait_span, "item in trait");
974-
}
975-
err.emit()
976-
}
969+
compare_const_impl(
970+
tcx,
971+
&ty_impl_item,
972+
impl_item.span,
973+
&ty_trait_item,
974+
impl_trait_ref,
975+
);
977976
}
978977
hir::ImplItemKind::Fn(..) => {
979978
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
980-
if ty_trait_item.kind == ty::AssocKind::Fn {
981-
compare_impl_method(
982-
tcx,
983-
&ty_impl_item,
984-
impl_item.span,
985-
&ty_trait_item,
986-
impl_trait_ref,
987-
opt_trait_span,
988-
);
989-
} else {
990-
let mut err = struct_span_err!(
991-
tcx.sess,
992-
impl_item.span,
993-
E0324,
994-
"item `{}` is an associated method, \
995-
which doesn't match its trait `{}`",
996-
ty_impl_item.ident,
997-
impl_trait_ref.print_only_trait_path()
998-
);
999-
err.span_label(impl_item.span, "does not match trait");
1000-
if let Some(trait_span) = opt_trait_span {
1001-
err.span_label(trait_span, "item in trait");
1002-
}
1003-
err.emit()
1004-
}
979+
compare_impl_method(
980+
tcx,
981+
&ty_impl_item,
982+
impl_item.span,
983+
&ty_trait_item,
984+
impl_trait_ref,
985+
opt_trait_span,
986+
);
1005987
}
1006988
hir::ImplItemKind::TyAlias(_) => {
1007989
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
1008-
if ty_trait_item.kind == ty::AssocKind::Type {
1009-
compare_ty_impl(
1010-
tcx,
1011-
&ty_impl_item,
1012-
impl_item.span,
1013-
&ty_trait_item,
1014-
impl_trait_ref,
1015-
opt_trait_span,
1016-
);
1017-
} else {
1018-
let mut err = struct_span_err!(
1019-
tcx.sess,
1020-
impl_item.span,
1021-
E0325,
1022-
"item `{}` is an associated type, \
1023-
which doesn't match its trait `{}`",
1024-
ty_impl_item.ident,
1025-
impl_trait_ref.print_only_trait_path()
1026-
);
1027-
err.span_label(impl_item.span, "does not match trait");
1028-
if let Some(trait_span) = opt_trait_span {
1029-
err.span_label(trait_span, "item in trait");
1030-
}
1031-
err.emit()
1032-
}
990+
compare_ty_impl(
991+
tcx,
992+
&ty_impl_item,
993+
impl_item.span,
994+
&ty_trait_item,
995+
impl_trait_ref,
996+
opt_trait_span,
997+
);
1033998
}
1034999
}
10351000

@@ -1040,6 +1005,8 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
10401005
impl_id.to_def_id(),
10411006
impl_item,
10421007
);
1008+
} else {
1009+
report_mismatch_error(tcx, ty_trait_item.def_id, impl_trait_ref, impl_item, &ty_impl_item);
10431010
}
10441011
}
10451012

@@ -1065,6 +1032,58 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
10651032
}
10661033
}
10671034

1035+
#[inline(never)]
1036+
#[cold]
1037+
fn report_mismatch_error<'tcx>(
1038+
tcx: TyCtxt<'tcx>,
1039+
trait_item_def_id: DefId,
1040+
impl_trait_ref: ty::TraitRef<'tcx>,
1041+
impl_item: &hir::ImplItem<'_>,
1042+
ty_impl_item: &ty::AssocItem,
1043+
) {
1044+
let mut err = match impl_item.kind {
1045+
hir::ImplItemKind::Const(..) => {
1046+
// Find associated const definition.
1047+
struct_span_err!(
1048+
tcx.sess,
1049+
impl_item.span,
1050+
E0323,
1051+
"item `{}` is an associated const, which doesn't match its trait `{}`",
1052+
ty_impl_item.ident,
1053+
impl_trait_ref.print_only_trait_path()
1054+
)
1055+
}
1056+
1057+
hir::ImplItemKind::Fn(..) => {
1058+
struct_span_err!(
1059+
tcx.sess,
1060+
impl_item.span,
1061+
E0324,
1062+
"item `{}` is an associated method, which doesn't match its trait `{}`",
1063+
ty_impl_item.ident,
1064+
impl_trait_ref.print_only_trait_path()
1065+
)
1066+
}
1067+
1068+
hir::ImplItemKind::TyAlias(_) => {
1069+
struct_span_err!(
1070+
tcx.sess,
1071+
impl_item.span,
1072+
E0325,
1073+
"item `{}` is an associated type, which doesn't match its trait `{}`",
1074+
ty_impl_item.ident,
1075+
impl_trait_ref.print_only_trait_path()
1076+
)
1077+
}
1078+
};
1079+
1080+
err.span_label(impl_item.span, "does not match trait");
1081+
if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
1082+
err.span_label(trait_span, "item in trait");
1083+
}
1084+
err.emit();
1085+
}
1086+
10681087
/// Checks whether a type can be represented in memory. In particular, it
10691088
/// identifies types that contain themselves without indirection through a
10701089
/// pointer, which would mean their size is unbounded.

0 commit comments

Comments
 (0)