@@ -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