@@ -48,6 +48,10 @@ crate fn compare_impl_method<'tcx>(
4848 return ;
4949 }
5050
51+ if let Err ( _) = compare_generic_param_kinds ( tcx, impl_m, trait_m, trait_item_span) {
52+ return ;
53+ }
54+
5155 if let Err ( _) =
5256 compare_number_of_method_arguments ( tcx, impl_m, impl_m_span, trait_m, trait_item_span)
5357 {
@@ -62,10 +66,6 @@ crate fn compare_impl_method<'tcx>(
6266 {
6367 return ;
6468 }
65-
66- if let Err ( _) = compare_const_param_types ( tcx, impl_m, trait_m, trait_item_span) {
67- return ;
68- }
6969}
7070
7171fn compare_predicate_entailment < ' tcx > (
@@ -914,62 +914,165 @@ fn compare_synthetic_generics<'tcx>(
914914 if let Some ( reported) = error_found { Err ( reported) } else { Ok ( ( ) ) }
915915}
916916
917- fn compare_const_param_types < ' tcx > (
917+ /// Checks that all parameters in the generics of a given assoc item in a trait impl have
918+ /// the same kind as the respective generic parameter in the trait def.
919+ ///
920+ /// For example all 4 errors in the following code are emitted here:
921+ /// ```
922+ /// trait Foo {
923+ /// fn foo<const N: u8>();
924+ /// type bar<const N: u8>;
925+ /// fn baz<const N: u32>();
926+ /// type blah<T>;
927+ /// }
928+ ///
929+ /// impl Foo for () {
930+ /// fn foo<const N: u64>() {}
931+ /// //~^ error
932+ /// type bar<const N: u64> {}
933+ /// //~^ error
934+ /// fn baz<T>() {}
935+ /// //~^ error
936+ /// type blah<const N: i64> = u32;
937+ /// //~^ error
938+ /// }
939+ /// ```
940+ ///
941+ /// This function does not handle lifetime parameters
942+ fn compare_generic_param_kinds < ' tcx > (
918943 tcx : TyCtxt < ' tcx > ,
919- impl_m : & ty:: AssocItem ,
920- trait_m : & ty:: AssocItem ,
944+ impl_item : & ty:: AssocItem ,
945+ trait_item : & ty:: AssocItem ,
921946 trait_item_span : Option < Span > ,
922947) -> Result < ( ) , ErrorGuaranteed > {
923- let const_params_of = |def_id| {
924- tcx. generics_of ( def_id) . params . iter ( ) . filter_map ( |param| match param. kind {
925- GenericParamDefKind :: Const { .. } => Some ( param. def_id ) ,
926- _ => None ,
948+ assert_eq ! ( impl_item. kind, trait_item. kind) ;
949+
950+ let ty_const_params_of = |def_id| {
951+ tcx. generics_of ( def_id) . params . iter ( ) . filter ( |param| {
952+ matches ! (
953+ param. kind,
954+ GenericParamDefKind :: Const { .. } | GenericParamDefKind :: Type { .. }
955+ )
927956 } )
928957 } ;
929- let const_params_impl = const_params_of ( impl_m. def_id ) ;
930- let const_params_trait = const_params_of ( trait_m. def_id ) ;
931-
932- for ( const_param_impl, const_param_trait) in iter:: zip ( const_params_impl, const_params_trait) {
933- let impl_ty = tcx. type_of ( const_param_impl) ;
934- let trait_ty = tcx. type_of ( const_param_trait) ;
935- if impl_ty != trait_ty {
936- let ( impl_span, impl_ident) = match tcx. hir ( ) . get_if_local ( const_param_impl) {
937- Some ( hir:: Node :: GenericParam ( hir:: GenericParam { span, name, .. } ) ) => (
938- span,
939- match name {
940- hir:: ParamName :: Plain ( ident) => Some ( ident) ,
941- _ => None ,
942- } ,
943- ) ,
944- other => bug ! (
945- "expected GenericParam, found {:?}" ,
946- other. map_or_else( || "nothing" . to_string( ) , |n| format!( "{:?}" , n) )
947- ) ,
948- } ;
949- let trait_span = match tcx. hir ( ) . get_if_local ( const_param_trait) {
950- Some ( hir:: Node :: GenericParam ( hir:: GenericParam { span, .. } ) ) => Some ( span) ,
951- _ => None ,
952- } ;
953- let mut err = struct_span_err ! (
954- tcx. sess,
955- * impl_span,
956- E0053 ,
957- "method `{}` has an incompatible const parameter type for trait" ,
958- trait_m. name
959- ) ;
960- err. span_note (
961- trait_span. map_or_else ( || trait_item_span. unwrap_or ( * impl_span) , |span| * span) ,
962- & format ! (
963- "the const parameter{} has type `{}`, but the declaration \
964- in trait `{}` has type `{}`",
965- & impl_ident. map_or_else( || "" . to_string( ) , |ident| format!( " `{ident}`" ) ) ,
966- impl_ty,
967- tcx. def_path_str( trait_m. def_id) ,
968- trait_ty
969- ) ,
970- ) ;
971- let reported = err. emit ( ) ;
972- return Err ( reported) ;
958+
959+ let get_param_span = |param : & ty:: GenericParamDef | match tcx. hir ( ) . get_if_local ( param. def_id ) {
960+ Some ( hir:: Node :: GenericParam ( hir:: GenericParam { span, .. } ) ) => Some ( span) ,
961+ _ => None ,
962+ } ;
963+
964+ let get_param_ident = |param : & ty:: GenericParamDef | match tcx. hir ( ) . get_if_local ( param. def_id ) {
965+ Some ( hir:: Node :: GenericParam ( hir:: GenericParam { name, .. } ) ) => match name {
966+ hir:: ParamName :: Plain ( ident) => Some ( ident) ,
967+ _ => None ,
968+ } ,
969+ other => bug ! (
970+ "expected GenericParam, found {:?}" ,
971+ other. map_or_else( || "nothing" . to_string( ) , |n| format!( "{:?}" , n) )
972+ ) ,
973+ } ;
974+
975+ let ty_const_params_impl = ty_const_params_of ( impl_item. def_id ) ;
976+ let ty_const_params_trait = ty_const_params_of ( trait_item. def_id ) ;
977+ let assoc_item_str = assoc_item_kind_str ( & impl_item) ;
978+
979+ for ( param_impl, param_trait) in iter:: zip ( ty_const_params_impl, ty_const_params_trait) {
980+ use GenericParamDefKind :: * ;
981+ match ( & param_impl. kind , & param_trait. kind ) {
982+ ( Const { .. } , Const { .. } ) => {
983+ let impl_ty = tcx. type_of ( param_impl. def_id ) ;
984+ let trait_ty = tcx. type_of ( param_trait. def_id ) ;
985+ if impl_ty != trait_ty {
986+ let param_impl_span = get_param_span ( param_impl) . unwrap ( ) ;
987+ let param_impl_ident = get_param_ident ( param_impl) ;
988+ let param_trait_span = get_param_span ( param_trait) ;
989+
990+ let mut err = struct_span_err ! (
991+ tcx. sess,
992+ * param_impl_span,
993+ E0053 ,
994+ "{} `{}` has an incompatible const parameter type for trait" ,
995+ assoc_item_str,
996+ trait_item. name,
997+ ) ;
998+ err. span_note (
999+ param_trait_span. map_or_else (
1000+ || trait_item_span. unwrap_or ( * param_impl_span) ,
1001+ |span| * span,
1002+ ) ,
1003+ & format ! (
1004+ "the const parameter{} has type `{}`, but the declaration \
1005+ in trait `{}` has type `{}`",
1006+ & param_impl_ident
1007+ . map_or_else( || "" . to_string( ) , |ident| format!( " `{ident}`" ) ) ,
1008+ impl_ty,
1009+ tcx. def_path_str( trait_item. def_id) ,
1010+ trait_ty
1011+ ) ,
1012+ ) ;
1013+ let reported = err. emit ( ) ;
1014+ return Err ( reported) ;
1015+ }
1016+ }
1017+ ( Const { .. } , Type { .. } ) => {
1018+ let impl_ty = tcx. type_of ( param_impl. def_id ) ;
1019+ let param_impl_span = get_param_span ( param_impl) . unwrap ( ) ;
1020+ let param_impl_ident = get_param_ident ( param_impl) ;
1021+ let param_trait_span = get_param_span ( param_trait) ;
1022+
1023+ let mut err = struct_span_err ! (
1024+ tcx. sess,
1025+ * param_impl_span,
1026+ E0053 ,
1027+ "{} `{}` has an incompatible generic parameter for trait" ,
1028+ assoc_item_str,
1029+ trait_item. name,
1030+ ) ;
1031+ err. span_note (
1032+ param_trait_span
1033+ . map_or_else ( || trait_item_span. unwrap_or ( * param_impl_span) , |span| * span) ,
1034+ & format ! (
1035+ "the trait impl specifies{} a const parameter of type `{}`, but the declaration \
1036+ in trait `{}` requires it is a type parameter",
1037+ & param_impl_ident
1038+ . map_or_else( || "" . to_string( ) , |ident| format!( " `{ident}` is" ) ) ,
1039+ impl_ty,
1040+ tcx. def_path_str( trait_item. def_id) ,
1041+ ) ,
1042+ ) ;
1043+ let reported = err. emit ( ) ;
1044+ return Err ( reported) ;
1045+ }
1046+ ( Type { .. } , Const { .. } ) => {
1047+ let trait_ty = tcx. type_of ( param_trait. def_id ) ;
1048+ let param_impl_span = get_param_span ( param_impl) . unwrap ( ) ;
1049+ let param_impl_ident = get_param_ident ( param_impl) ;
1050+ let param_trait_span = get_param_span ( param_trait) ;
1051+
1052+ let mut err = struct_span_err ! (
1053+ tcx. sess,
1054+ * param_impl_span,
1055+ E0053 ,
1056+ "{} `{}` has an incompatible generic parameter for trait" ,
1057+ assoc_item_str,
1058+ trait_item. name,
1059+ ) ;
1060+ err. span_note (
1061+ param_trait_span
1062+ . map_or_else ( || trait_item_span. unwrap_or ( * param_impl_span) , |span| * span) ,
1063+ & format ! (
1064+ "the trait impl specifies{} a type parameter, but the declaration \
1065+ in trait `{}` requires it is a const parameter of type `{}`",
1066+ & param_impl_ident
1067+ . map_or_else( || "" . to_string( ) , |ident| format!( " `{ident}` is" ) ) ,
1068+ tcx. def_path_str( trait_item. def_id) ,
1069+ trait_ty,
1070+ ) ,
1071+ ) ;
1072+ let reported = err. emit ( ) ;
1073+ return Err ( reported) ;
1074+ }
1075+ _ => ( ) ,
9731076 }
9741077 }
9751078
@@ -1095,6 +1198,8 @@ crate fn compare_ty_impl<'tcx>(
10951198 let _: Result < ( ) , ErrorGuaranteed > = ( || {
10961199 compare_number_of_generics ( tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span) ?;
10971200
1201+ compare_generic_param_kinds ( tcx, impl_ty, trait_ty, trait_item_span) ?;
1202+
10981203 let sp = tcx. def_span ( impl_ty. def_id ) ;
10991204 compare_type_predicate_entailment ( tcx, impl_ty, sp, trait_ty, impl_trait_ref) ?;
11001205
0 commit comments