@@ -1921,33 +1921,102 @@ fn report_bivariance<'tcx>(
1921
1921
item,
1922
1922
) ;
1923
1923
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 ( )
1924
+ if !usage_spans. is_empty ( ) {
1925
+ // First, check if the ADT is (probably) cyclical. We say probably here, since
1926
+ // we're not actually looking into substitutions, just walking through fields.
1927
+ // And we only recurse into the fields of ADTs, and not the hidden types of
1928
+ // opaques or anything else fancy.
1929
+ let item_def_id = item. owner_id . to_def_id ( ) ;
1930
+ let is_probably_cyclical = if matches ! (
1931
+ tcx. def_kind( item_def_id) ,
1932
+ DefKind :: Struct | DefKind :: Union | DefKind :: Enum
1933
+ ) {
1934
+ IsProbablyCyclical { tcx, adt_def_id : item_def_id, seen : Default :: default ( ) }
1935
+ . visit_all_fields ( tcx. adt_def ( item_def_id) )
1936
+ . is_break ( )
1937
+ } else {
1938
+ false
1939
+ } ;
1940
+ // If the ADT is cyclical, then if at least one usage of the type parameter or
1941
+ // the `Self` alias is present in the, then it's probably a cyclical struct, and
1942
+ // we should call those parameter usages recursive rather than just saying they're
1943
+ // unused...
1944
+ //
1945
+ // We currently report *all* of the parameter usages, since computing the exact
1946
+ // subset is very involved, and the fact we're mentioning recursion at all is
1947
+ // likely to guide the user in the right direction.
1948
+ if is_probably_cyclical {
1949
+ let diag = tcx. dcx ( ) . create_err ( errors:: RecursiveGenericParameter {
1950
+ spans : usage_spans,
1951
+ param_span : param. span ,
1952
+ param_name,
1953
+ param_def_kind : tcx. def_descr ( param. def_id . to_def_id ( ) ) ,
1954
+ help,
1955
+ note : ( ) ,
1956
+ } ) ;
1957
+ return diag. emit ( ) ;
1958
+ }
1959
+ }
1960
+
1961
+ let const_param_help =
1962
+ matches ! ( param. kind, hir:: GenericParamKind :: Type { .. } if !has_explicit_bounds)
1963
+ . then_some ( ( ) ) ;
1964
+
1965
+ let mut diag = tcx. dcx ( ) . create_err ( errors:: UnusedGenericParameter {
1966
+ span : param. span ,
1967
+ param_name,
1968
+ param_def_kind : tcx. def_descr ( param. def_id . to_def_id ( ) ) ,
1969
+ usage_spans,
1970
+ help,
1971
+ const_param_help,
1972
+ } ) ;
1973
+ diag. code ( E0392 ) ;
1974
+ diag. emit ( )
1975
+ }
1976
+
1977
+ /// Detects cases where an ADT is trivially cyclical -- we want to detect this so
1978
+ /// /we only mention that its parameters are used cyclically if the ADT is truly
1979
+ /// cyclical.
1980
+ ///
1981
+ /// Notably, we don't consider substitutions here, so this may have false positives.
1982
+ struct IsProbablyCyclical < ' tcx > {
1983
+ tcx : TyCtxt < ' tcx > ,
1984
+ adt_def_id : DefId ,
1985
+ seen : FxHashSet < DefId > ,
1986
+ }
1987
+
1988
+ impl < ' tcx > IsProbablyCyclical < ' tcx > {
1989
+ fn visit_all_fields ( & mut self , adt_def : ty:: AdtDef < ' tcx > ) -> ControlFlow < ( ) , ( ) > {
1990
+ for field in adt_def. all_fields ( ) {
1991
+ self . tcx . type_of ( field. did ) . instantiate_identity ( ) . visit_with ( self ) ?;
1992
+ }
1993
+
1994
+ ControlFlow :: Continue ( ( ) )
1948
1995
}
1949
1996
}
1950
1997
1998
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for IsProbablyCyclical < ' tcx > {
1999
+ type Result = ControlFlow < ( ) , ( ) > ;
2000
+
2001
+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < ( ) , ( ) > {
2002
+ if let Some ( adt_def) = t. ty_adt_def ( ) {
2003
+ if adt_def. did ( ) == self . adt_def_id {
2004
+ return ControlFlow :: Break ( ( ) ) ;
2005
+ }
2006
+
2007
+ if self . seen . insert ( adt_def. did ( ) ) {
2008
+ self . visit_all_fields ( adt_def) ?;
2009
+ }
2010
+ }
2011
+
2012
+ t. super_visit_with ( self )
2013
+ }
2014
+ }
2015
+
2016
+ /// Collect usages of the `param_def_id` and `Res::SelfTyAlias` in the HIR.
2017
+ ///
2018
+ /// This is used to report places where the user has used parameters in a
2019
+ /// non-variance-constraining way for better bivariance errors.
1951
2020
struct CollectUsageSpans < ' a > {
1952
2021
spans : & ' a mut Vec < Span > ,
1953
2022
param_def_id : DefId ,
0 commit comments