@@ -7,10 +7,10 @@ use rustc_hir::intravisit;
77use rustc_hir:: { GenericParamKind , ImplItemKind , TraitItemKind } ;
88use rustc_infer:: infer:: { self , InferOk , TyCtxtInferExt } ;
99use rustc_infer:: traits:: util;
10- use rustc_middle:: ty;
1110use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
1211use rustc_middle:: ty:: subst:: { InternalSubsts , Subst } ;
1312use rustc_middle:: ty:: util:: ExplicitSelf ;
13+ use rustc_middle:: ty:: { self , DefIdTree } ;
1414use rustc_middle:: ty:: { GenericParamDefKind , ToPredicate , TyCtxt } ;
1515use rustc_span:: Span ;
1616use rustc_trait_selection:: traits:: error_reporting:: InferCtxtExt ;
@@ -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) {
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 > (
@@ -579,6 +579,27 @@ fn compare_self_type<'tcx>(
579579 Ok ( ( ) )
580580}
581581
582+ /// Checks that the number of generics on a given assoc item in a trait impl is the same
583+ /// as the number of generics on the respective assoc item in the trait definition.
584+ ///
585+ /// For example this code emits the errors in the following code:
586+ /// ```
587+ /// trait Trait {
588+ /// fn foo();
589+ /// type Assoc<T>;
590+ /// }
591+ ///
592+ /// impl Trait for () {
593+ /// fn foo<T>() {}
594+ /// //~^ error
595+ /// type Assoc = u32;
596+ /// //~^ error
597+ /// }
598+ /// ```
599+ ///
600+ /// Notably this does not error on `foo<T>` implemented as `foo<const N: u8>` or
601+ /// `foo<const N: u8>` implemented as `foo<const N: u32>`. This is handled in
602+ /// [`compare_generic_param_kinds`]. This function also does not handle lifetime parameters
582603fn compare_number_of_generics < ' tcx > (
583604 tcx : TyCtxt < ' tcx > ,
584605 impl_ : & ty:: AssocItem ,
@@ -589,6 +610,15 @@ fn compare_number_of_generics<'tcx>(
589610 let trait_own_counts = tcx. generics_of ( trait_. def_id ) . own_counts ( ) ;
590611 let impl_own_counts = tcx. generics_of ( impl_. def_id ) . own_counts ( ) ;
591612
613+ // This avoids us erroring on `foo<T>` implemented as `foo<const N: u8>` as this is implemented
614+ // in `compare_generic_param_kinds` which will give a nicer error message than something like:
615+ // "expected 1 type parameter, found 0 type parameters"
616+ if ( trait_own_counts. types + trait_own_counts. consts )
617+ == ( impl_own_counts. types + impl_own_counts. consts )
618+ {
619+ return Ok ( ( ) ) ;
620+ }
621+
592622 let matchings = [
593623 ( "type" , trait_own_counts. types , impl_own_counts. types ) ,
594624 ( "const" , trait_own_counts. consts , impl_own_counts. consts ) ,
@@ -914,60 +944,93 @@ fn compare_synthetic_generics<'tcx>(
914944 if let Some ( reported) = error_found { Err ( reported) } else { Ok ( ( ) ) }
915945}
916946
917- fn compare_const_param_types < ' tcx > (
947+ /// Checks that all parameters in the generics of a given assoc item in a trait impl have
948+ /// the same kind as the respective generic parameter in the trait def.
949+ ///
950+ /// For example all 4 errors in the following code are emitted here:
951+ /// ```
952+ /// trait Foo {
953+ /// fn foo<const N: u8>();
954+ /// type bar<const N: u8>;
955+ /// fn baz<const N: u32>();
956+ /// type blah<T>;
957+ /// }
958+ ///
959+ /// impl Foo for () {
960+ /// fn foo<const N: u64>() {}
961+ /// //~^ error
962+ /// type bar<const N: u64> {}
963+ /// //~^ error
964+ /// fn baz<T>() {}
965+ /// //~^ error
966+ /// type blah<const N: i64> = u32;
967+ /// //~^ error
968+ /// }
969+ /// ```
970+ ///
971+ /// This function does not handle lifetime parameters
972+ fn compare_generic_param_kinds < ' tcx > (
918973 tcx : TyCtxt < ' tcx > ,
919- impl_m : & ty:: AssocItem ,
920- trait_m : & ty:: AssocItem ,
921- trait_item_span : Option < Span > ,
974+ impl_item : & ty:: AssocItem ,
975+ trait_item : & ty:: AssocItem ,
922976) -> 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 ,
977+ assert_eq ! ( impl_item. kind, trait_item. kind) ;
978+
979+ let ty_const_params_of = |def_id| {
980+ tcx. generics_of ( def_id) . params . iter ( ) . filter ( |param| {
981+ matches ! (
982+ param. kind,
983+ GenericParamDefKind :: Const { .. } | GenericParamDefKind :: Type { .. }
984+ )
927985 } )
928986 } ;
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- } ;
987+
988+ for ( param_impl, param_trait) in
989+ iter:: zip ( ty_const_params_of ( impl_item. def_id ) , ty_const_params_of ( trait_item. def_id ) )
990+ {
991+ use GenericParamDefKind :: * ;
992+ if match ( & param_impl. kind , & param_trait. kind ) {
993+ ( Const { .. } , Const { .. } )
994+ if tcx. type_of ( param_impl. def_id ) != tcx. type_of ( param_trait. def_id ) =>
995+ {
996+ true
997+ }
998+ ( Const { .. } , Type { .. } ) | ( Type { .. } , Const { .. } ) => true ,
999+ // this is exhaustive so that anyone adding new generic param kinds knows
1000+ // to make sure this error is reported for them.
1001+ ( Const { .. } , Const { .. } ) | ( Type { .. } , Type { .. } ) => false ,
1002+ ( Lifetime { .. } , _) | ( _, Lifetime { .. } ) => unreachable ! ( ) ,
1003+ } {
1004+ let param_impl_span = tcx. def_span ( param_impl. def_id ) ;
1005+ let param_trait_span = tcx. def_span ( param_trait. def_id ) ;
1006+
9531007 let mut err = struct_span_err ! (
9541008 tcx. sess,
955- * impl_span ,
1009+ param_impl_span ,
9561010 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- ) ,
1011+ "{} `{}` has an incompatible generic parameter for trait `{}`" ,
1012+ assoc_item_kind_str( & impl_item) ,
1013+ trait_item. name,
1014+ & tcx. def_path_str( tcx. parent( trait_item. def_id) )
9701015 ) ;
1016+
1017+ let make_param_message = |prefix : & str , param : & ty:: GenericParamDef | match param. kind {
1018+ Const { .. } => {
1019+ format ! ( "{} const parameter of type `{}`" , prefix, tcx. type_of( param. def_id) )
1020+ }
1021+ Type { .. } => format ! ( "{} type parameter" , prefix) ,
1022+ Lifetime { .. } => unreachable ! ( ) ,
1023+ } ;
1024+
1025+ let trait_header_span = tcx. def_ident_span ( tcx. parent ( trait_item. def_id ) ) . unwrap ( ) ;
1026+ err. span_label ( trait_header_span, "" ) ;
1027+ err. span_label ( param_trait_span, make_param_message ( "expected" , param_trait) ) ;
1028+
1029+ let impl_header_span =
1030+ tcx. sess . source_map ( ) . guess_head_span ( tcx. def_span ( tcx. parent ( impl_item. def_id ) ) ) ;
1031+ err. span_label ( impl_header_span, "" ) ;
1032+ err. span_label ( param_impl_span, make_param_message ( "found" , param_impl) ) ;
1033+
9711034 let reported = err. emit ( ) ;
9721035 return Err ( reported) ;
9731036 }
@@ -1095,6 +1158,8 @@ crate fn compare_ty_impl<'tcx>(
10951158 let _: Result < ( ) , ErrorGuaranteed > = ( || {
10961159 compare_number_of_generics ( tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span) ?;
10971160
1161+ compare_generic_param_kinds ( tcx, impl_ty, trait_ty) ?;
1162+
10981163 let sp = tcx. def_span ( impl_ty. def_id ) ;
10991164 compare_type_predicate_entailment ( tcx, impl_ty, sp, trait_ty, impl_trait_ref) ?;
11001165
0 commit comments