@@ -846,21 +846,13 @@ pub(super) fn check_specialization_validity<'tcx>(
846
846
Ok ( ancestors) => ancestors,
847
847
Err ( _) => return ,
848
848
} ;
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
+ } ) ;
864
856
865
857
let opt_result = ancestor_impls. find_map ( |( parent_impl, parent_item) | {
866
858
match parent_item {
@@ -902,8 +894,6 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
902
894
impl_trait_ref : ty:: TraitRef < ' tcx > ,
903
895
impl_item_refs : & [ hir:: ImplItemRef < ' _ > ] ,
904
896
) {
905
- let impl_span = tcx. sess . source_map ( ) . guess_head_span ( full_impl_span) ;
906
-
907
897
// If the trait reference itself is erroneous (so the compilation is going
908
898
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
909
899
// isn't populated for such impls.
@@ -931,111 +921,75 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
931
921
932
922
// Locate trait definition and items
933
923
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 ) ;
936
926
937
927
// Check existing impl methods to see if they are both present in trait
938
928
// 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 {
941
930
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 {
954
961
match impl_item. kind {
955
962
hir:: ImplItemKind :: Const ( ..) => {
956
963
// 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
+ ) ;
983
971
}
984
972
hir:: ImplItemKind :: Fn ( ..) => {
985
973
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
+ ) ;
1011
982
}
1012
983
hir:: ImplItemKind :: TyAlias ( _) => {
1013
984
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
+ ) ;
1039
993
}
1040
994
}
1041
995
@@ -1046,12 +1000,22 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
1046
1000
impl_id. to_def_id ( ) ,
1047
1001
impl_item,
1048
1002
) ;
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
+ ) ;
1049
1011
}
1050
1012
}
1051
1013
1052
- // Check for missing items from trait
1053
- let mut missing_items = Vec :: new ( ) ;
1054
1014
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 ( ) ;
1055
1019
for trait_item in tcx. associated_items ( impl_trait_ref. def_id ) . in_definition_order ( ) {
1056
1020
let is_implemented = ancestors
1057
1021
. leaf_def ( tcx, trait_item. ident , trait_item. kind )
@@ -1064,11 +1028,63 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
1064
1028
}
1065
1029
}
1066
1030
}
1031
+
1032
+ if !missing_items. is_empty ( ) {
1033
+ missing_items_err ( tcx, impl_span, & missing_items, full_impl_span) ;
1034
+ }
1067
1035
}
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
+ }
1068
1070
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" ) ;
1071
1086
}
1087
+ err. emit ( ) ;
1072
1088
}
1073
1089
1074
1090
/// Checks whether a type can be represented in memory. In particular, it
0 commit comments