@@ -1921,33 +1921,102 @@ fn report_bivariance<'tcx>(
19211921 item,
19221922 ) ;
19231923
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 ( ( ) )
19481995 }
19491996}
19501997
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.
19512020struct CollectUsageSpans < ' a > {
19522021 spans : & ' a mut Vec < Span > ,
19532022 param_def_id : DefId ,
0 commit comments