@@ -7,10 +7,10 @@ use rustc_hir::intravisit;
7
7
use rustc_hir:: { GenericParamKind , ImplItemKind , TraitItemKind } ;
8
8
use rustc_infer:: infer:: { self , InferOk , TyCtxtInferExt } ;
9
9
use rustc_infer:: traits:: util;
10
- use rustc_middle:: ty;
11
10
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
12
11
use rustc_middle:: ty:: subst:: { InternalSubsts , Subst } ;
13
12
use rustc_middle:: ty:: util:: ExplicitSelf ;
13
+ use rustc_middle:: ty:: { self , DefIdTree } ;
14
14
use rustc_middle:: ty:: { GenericParamDefKind , ToPredicate , TyCtxt } ;
15
15
use rustc_span:: Span ;
16
16
use rustc_trait_selection:: traits:: error_reporting:: InferCtxtExt ;
@@ -48,6 +48,10 @@ crate fn compare_impl_method<'tcx>(
48
48
return ;
49
49
}
50
50
51
+ if let Err ( _) = compare_generic_param_kinds ( tcx, impl_m, trait_m) {
52
+ return ;
53
+ }
54
+
51
55
if let Err ( _) =
52
56
compare_number_of_method_arguments ( tcx, impl_m, impl_m_span, trait_m, trait_item_span)
53
57
{
@@ -62,10 +66,6 @@ crate fn compare_impl_method<'tcx>(
62
66
{
63
67
return ;
64
68
}
65
-
66
- if let Err ( _) = compare_const_param_types ( tcx, impl_m, trait_m, trait_item_span) {
67
- return ;
68
- }
69
69
}
70
70
71
71
fn compare_predicate_entailment < ' tcx > (
@@ -579,6 +579,27 @@ fn compare_self_type<'tcx>(
579
579
Ok ( ( ) )
580
580
}
581
581
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
582
603
fn compare_number_of_generics < ' tcx > (
583
604
tcx : TyCtxt < ' tcx > ,
584
605
impl_ : & ty:: AssocItem ,
@@ -589,6 +610,15 @@ fn compare_number_of_generics<'tcx>(
589
610
let trait_own_counts = tcx. generics_of ( trait_. def_id ) . own_counts ( ) ;
590
611
let impl_own_counts = tcx. generics_of ( impl_. def_id ) . own_counts ( ) ;
591
612
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
+
592
622
let matchings = [
593
623
( "type" , trait_own_counts. types , impl_own_counts. types ) ,
594
624
( "const" , trait_own_counts. consts , impl_own_counts. consts ) ,
@@ -914,60 +944,93 @@ fn compare_synthetic_generics<'tcx>(
914
944
if let Some ( reported) = error_found { Err ( reported) } else { Ok ( ( ) ) }
915
945
}
916
946
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 > (
918
973
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 ,
922
976
) -> 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
+ )
927
985
} )
928
986
} ;
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
+
953
1007
let mut err = struct_span_err ! (
954
1008
tcx. sess,
955
- * impl_span ,
1009
+ param_impl_span ,
956
1010
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) )
970
1015
) ;
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
+
971
1034
let reported = err. emit ( ) ;
972
1035
return Err ( reported) ;
973
1036
}
@@ -1095,6 +1158,8 @@ crate fn compare_ty_impl<'tcx>(
1095
1158
let _: Result < ( ) , ErrorGuaranteed > = ( || {
1096
1159
compare_number_of_generics ( tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span) ?;
1097
1160
1161
+ compare_generic_param_kinds ( tcx, impl_ty, trait_ty) ?;
1162
+
1098
1163
let sp = tcx. def_span ( impl_ty. def_id ) ;
1099
1164
compare_type_predicate_entailment ( tcx, impl_ty, sp, trait_ty, impl_trait_ref) ?;
1100
1165
0 commit comments