@@ -4,12 +4,12 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par
4
4
use crate :: errors;
5
5
use crate :: fluent_generated as fluent;
6
6
7
- use hir:: intravisit:: Visitor ;
7
+ use hir:: intravisit:: { self , Visitor } ;
8
8
use rustc_ast as ast;
9
9
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexSet } ;
10
10
use rustc_errors:: { codes:: * , pluralize, struct_span_code_err, Applicability , ErrorGuaranteed } ;
11
11
use rustc_hir as hir;
12
- use rustc_hir:: def:: DefKind ;
12
+ use rustc_hir:: def:: { DefKind , Res } ;
13
13
use rustc_hir:: def_id:: { DefId , LocalDefId , LocalModDefId } ;
14
14
use rustc_hir:: lang_items:: LangItem ;
15
15
use rustc_hir:: ItemKind ;
@@ -1799,7 +1799,7 @@ fn receiver_is_implemented<'tcx>(
1799
1799
1800
1800
fn check_variances_for_type_defn < ' tcx > (
1801
1801
tcx : TyCtxt < ' tcx > ,
1802
- item : & hir:: Item < ' tcx > ,
1802
+ item : & ' tcx hir:: Item < ' tcx > ,
1803
1803
hir_generics : & hir:: Generics < ' tcx > ,
1804
1804
) {
1805
1805
let identity_args = ty:: GenericArgs :: identity_for_item ( tcx, item. owner_id ) ;
@@ -1886,21 +1886,21 @@ fn check_variances_for_type_defn<'tcx>(
1886
1886
hir:: ParamName :: Error => { }
1887
1887
_ => {
1888
1888
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) ;
1890
1890
}
1891
1891
}
1892
1892
}
1893
1893
}
1894
1894
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 > ,
1898
1898
has_explicit_bounds : bool ,
1899
- item_kind : ItemKind < ' _ > ,
1899
+ item : & ' tcx hir :: Item < ' tcx > ,
1900
1900
) -> ErrorGuaranteed {
1901
1901
let param_name = param. name . ident ( ) ;
1902
1902
1903
- let help = match item_kind {
1903
+ let help = match item . kind {
1904
1904
ItemKind :: Enum ( ..) | ItemKind :: Struct ( ..) | ItemKind :: Union ( ..) => {
1905
1905
if let Some ( def_id) = tcx. lang_items ( ) . phantom_data ( ) {
1906
1906
errors:: UnusedGenericParameterHelp :: Adt {
@@ -1915,6 +1915,49 @@ fn report_bivariance(
1915
1915
item_kind => bug ! ( "report_bivariance: unexpected item kind: {item_kind:?}" ) ,
1916
1916
} ;
1917
1917
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
+ ) ;
1923
+
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
+
1918
1961
let const_param_help =
1919
1962
matches ! ( param. kind, hir:: GenericParamKind :: Type { .. } if !has_explicit_bounds)
1920
1963
. then_some ( ( ) ) ;
@@ -1923,13 +1966,85 @@ fn report_bivariance(
1923
1966
span : param. span ,
1924
1967
param_name,
1925
1968
param_def_kind : tcx. def_descr ( param. def_id . to_def_id ( ) ) ,
1969
+ usage_spans,
1926
1970
help,
1927
1971
const_param_help,
1928
1972
} ) ;
1929
1973
diag. code ( E0392 ) ;
1930
1974
diag. emit ( )
1931
1975
}
1932
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 ( ( ) )
1995
+ }
1996
+ }
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.
2020
+ struct CollectUsageSpans < ' a > {
2021
+ spans : & ' a mut Vec < Span > ,
2022
+ param_def_id : DefId ,
2023
+ }
2024
+
2025
+ impl < ' tcx > Visitor < ' tcx > for CollectUsageSpans < ' _ > {
2026
+ type Result = ( ) ;
2027
+
2028
+ fn visit_generics ( & mut self , _g : & ' tcx rustc_hir:: Generics < ' tcx > ) -> Self :: Result {
2029
+ // Skip the generics. We only care about fields, not where clause/param bounds.
2030
+ }
2031
+
2032
+ fn visit_ty ( & mut self , t : & ' tcx hir:: Ty < ' tcx > ) -> Self :: Result {
2033
+ if let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , qpath) ) = t. kind {
2034
+ if let Res :: Def ( DefKind :: TyParam , def_id) = qpath. res
2035
+ && def_id == self . param_def_id
2036
+ {
2037
+ self . spans . push ( t. span ) ;
2038
+ return ;
2039
+ } else if let Res :: SelfTyAlias { .. } = qpath. res {
2040
+ self . spans . push ( t. span ) ;
2041
+ return ;
2042
+ }
2043
+ }
2044
+ intravisit:: walk_ty ( self , t) ;
2045
+ }
2046
+ }
2047
+
1933
2048
impl < ' tcx > WfCheckingCtxt < ' _ , ' tcx > {
1934
2049
/// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that
1935
2050
/// aren't true.
0 commit comments