@@ -4,12 +4,12 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par
44use crate :: errors;
55use crate :: fluent_generated as fluent;
66
7- use hir:: intravisit:: Visitor ;
7+ use hir:: intravisit:: { self , Visitor } ;
88use rustc_ast as ast;
99use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexSet } ;
1010use rustc_errors:: { codes:: * , pluralize, struct_span_code_err, Applicability , ErrorGuaranteed } ;
1111use rustc_hir as hir;
12- use rustc_hir:: def:: DefKind ;
12+ use rustc_hir:: def:: { DefKind , Res } ;
1313use rustc_hir:: def_id:: { DefId , LocalDefId , LocalModDefId } ;
1414use rustc_hir:: lang_items:: LangItem ;
1515use rustc_hir:: ItemKind ;
@@ -1799,7 +1799,7 @@ fn receiver_is_implemented<'tcx>(
17991799
18001800fn check_variances_for_type_defn < ' tcx > (
18011801 tcx : TyCtxt < ' tcx > ,
1802- item : & hir:: Item < ' tcx > ,
1802+ item : & ' tcx hir:: Item < ' tcx > ,
18031803 hir_generics : & hir:: Generics < ' tcx > ,
18041804) {
18051805 let identity_args = ty:: GenericArgs :: identity_for_item ( tcx, item. owner_id ) ;
@@ -1886,21 +1886,21 @@ fn check_variances_for_type_defn<'tcx>(
18861886 hir:: ParamName :: Error => { }
18871887 _ => {
18881888 let has_explicit_bounds = explicitly_bounded_params. contains ( & parameter) ;
1889- report_bivariance ( tcx, hir_param, has_explicit_bounds, item. kind ) ;
1889+ report_bivariance ( tcx, hir_param, has_explicit_bounds, item) ;
18901890 }
18911891 }
18921892 }
18931893}
18941894
1895- fn report_bivariance (
1896- tcx : TyCtxt < ' _ > ,
1897- param : & rustc_hir :: GenericParam < ' _ > ,
1895+ fn report_bivariance < ' tcx > (
1896+ tcx : TyCtxt < ' tcx > ,
1897+ param : & ' tcx hir :: GenericParam < ' tcx > ,
18981898 has_explicit_bounds : bool ,
1899- item_kind : ItemKind < ' _ > ,
1899+ item : & ' tcx hir :: Item < ' tcx > ,
19001900) -> ErrorGuaranteed {
19011901 let param_name = param. name . ident ( ) ;
19021902
1903- let help = match item_kind {
1903+ let help = match item . kind {
19041904 ItemKind :: Enum ( ..) | ItemKind :: Struct ( ..) | ItemKind :: Union ( ..) => {
19051905 if let Some ( def_id) = tcx. lang_items ( ) . phantom_data ( ) {
19061906 errors:: UnusedGenericParameterHelp :: Adt {
@@ -1915,19 +1915,60 @@ fn report_bivariance(
19151915 item_kind => bug ! ( "report_bivariance: unexpected item kind: {item_kind:?}" ) ,
19161916 } ;
19171917
1918- let const_param_help =
1919- matches ! ( param. kind, hir:: GenericParamKind :: Type { .. } if !has_explicit_bounds)
1920- . then_some ( ( ) ) ;
1918+ let mut usage_spans = vec ! [ ] ;
1919+ intravisit:: walk_item (
1920+ & mut CollectUsageSpans { spans : & mut usage_spans, param_def_id : param. def_id . to_def_id ( ) } ,
1921+ item,
1922+ ) ;
19211923
1922- let mut diag = tcx. dcx ( ) . create_err ( errors:: UnusedGenericParameter {
1923- span : param. span ,
1924- param_name,
1925- param_def_kind : tcx. def_descr ( param. def_id . to_def_id ( ) ) ,
1926- help,
1927- const_param_help,
1928- } ) ;
1929- diag. code ( E0392 ) ;
1930- diag. emit ( )
1924+ if usage_spans. is_empty ( ) {
1925+ let const_param_help =
1926+ matches ! ( param. kind, hir:: GenericParamKind :: Type { .. } if !has_explicit_bounds)
1927+ . then_some ( ( ) ) ;
1928+
1929+ let mut diag = tcx. dcx ( ) . create_err ( errors:: UnusedGenericParameter {
1930+ span : param. span ,
1931+ param_name,
1932+ param_def_kind : tcx. def_descr ( param. def_id . to_def_id ( ) ) ,
1933+ help,
1934+ const_param_help,
1935+ } ) ;
1936+ diag. code ( E0392 ) ;
1937+ diag. emit ( )
1938+ } else {
1939+ let diag = tcx. dcx ( ) . create_err ( errors:: RecursiveGenericParameter {
1940+ spans : usage_spans,
1941+ param_span : param. span ,
1942+ param_name,
1943+ param_def_kind : tcx. def_descr ( param. def_id . to_def_id ( ) ) ,
1944+ help,
1945+ note : ( ) ,
1946+ } ) ;
1947+ diag. emit ( )
1948+ }
1949+ }
1950+
1951+ struct CollectUsageSpans < ' a > {
1952+ spans : & ' a mut Vec < Span > ,
1953+ param_def_id : DefId ,
1954+ }
1955+
1956+ impl < ' tcx > Visitor < ' tcx > for CollectUsageSpans < ' _ > {
1957+ type Result = ( ) ;
1958+
1959+ fn visit_generics ( & mut self , _g : & ' tcx rustc_hir:: Generics < ' tcx > ) -> Self :: Result {
1960+ // Skip the generics. We only care about fields, not where clause/param bounds.
1961+ }
1962+
1963+ fn visit_ty ( & mut self , t : & ' tcx hir:: Ty < ' tcx > ) -> Self :: Result {
1964+ if let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , qpath) ) = t. kind
1965+ && let Res :: Def ( DefKind :: TyParam , def_id) = qpath. res
1966+ && def_id == self . param_def_id
1967+ {
1968+ self . spans . push ( t. span ) ;
1969+ }
1970+ intravisit:: walk_ty ( self , t) ;
1971+ }
19311972}
19321973
19331974impl < ' tcx > WfCheckingCtxt < ' _ , ' tcx > {
0 commit comments