@@ -8,11 +8,13 @@ use rustc_ast as ast;
88use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexSet } ;
99use rustc_errors:: { codes:: * , pluralize, struct_span_code_err, Applicability , ErrorGuaranteed } ;
1010use rustc_hir as hir;
11+ use rustc_hir:: def:: DefKind ;
1112use rustc_hir:: def_id:: { DefId , LocalDefId , LocalModDefId } ;
1213use rustc_hir:: lang_items:: LangItem ;
1314use rustc_hir:: ItemKind ;
1415use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
1516use rustc_infer:: infer:: { self , InferCtxt , TyCtxtInferExt } ;
17+ use rustc_macros:: LintDiagnostic ;
1618use rustc_middle:: query:: Providers ;
1719use rustc_middle:: ty:: print:: with_no_trimmed_paths;
1820use rustc_middle:: ty:: trait_def:: TraitSpecializationKind ;
@@ -136,6 +138,8 @@ where
136138 infcx. implied_bounds_tys_compat ( param_env, body_def_id, & assumed_wf_types, false ) ;
137139 let outlives_env = OutlivesEnvironment :: with_bounds ( param_env, implied_bounds) ;
138140
141+ lint_redundant_lifetimes ( tcx, body_def_id, & outlives_env) ;
142+
139143 let errors = infcx. resolve_regions ( & outlives_env) ;
140144 if errors. is_empty ( ) {
141145 return Ok ( ( ) ) ;
@@ -2010,6 +2014,130 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error
20102014 res
20112015}
20122016
2017+ fn lint_redundant_lifetimes < ' tcx > (
2018+ tcx : TyCtxt < ' tcx > ,
2019+ owner_id : LocalDefId ,
2020+ outlives_env : & OutlivesEnvironment < ' tcx > ,
2021+ ) {
2022+ let def_kind = tcx. def_kind ( owner_id) ;
2023+ match def_kind {
2024+ DefKind :: Struct
2025+ | DefKind :: Union
2026+ | DefKind :: Enum
2027+ | DefKind :: Trait
2028+ | DefKind :: TraitAlias
2029+ | DefKind :: Fn
2030+ | DefKind :: Const
2031+ | DefKind :: Impl { of_trait : false } => {
2032+ // Proceed
2033+ }
2034+ DefKind :: AssocFn | DefKind :: AssocTy | DefKind :: AssocConst => {
2035+ let parent_def_id = tcx. local_parent ( owner_id) ;
2036+ if matches ! ( tcx. def_kind( parent_def_id) , DefKind :: Impl { of_trait: true } ) {
2037+ // Don't check for redundant lifetimes for trait implementations,
2038+ // since the signature is required to be compatible with the trait.
2039+ return ;
2040+ }
2041+ }
2042+ DefKind :: Impl { of_trait : true }
2043+ | DefKind :: Mod
2044+ | DefKind :: Variant
2045+ | DefKind :: TyAlias
2046+ | DefKind :: ForeignTy
2047+ | DefKind :: TyParam
2048+ | DefKind :: ConstParam
2049+ | DefKind :: Static { .. }
2050+ | DefKind :: Ctor ( _, _)
2051+ | DefKind :: Macro ( _)
2052+ | DefKind :: ExternCrate
2053+ | DefKind :: Use
2054+ | DefKind :: ForeignMod
2055+ | DefKind :: AnonConst
2056+ | DefKind :: InlineConst
2057+ | DefKind :: OpaqueTy
2058+ | DefKind :: Field
2059+ | DefKind :: LifetimeParam
2060+ | DefKind :: GlobalAsm
2061+ | DefKind :: Closure => return ,
2062+ }
2063+
2064+ // The ordering of this lifetime map is a bit subtle.
2065+ //
2066+ // Specifically, we want to find a "candidate" lifetime that precedes a "victim" lifetime,
2067+ // where we can prove that `'candidate = 'victim`.
2068+ //
2069+ // `'static` must come first in this list because we can never replace `'static` with
2070+ // something else, but if we find some lifetime `'a` where `'a = 'static`, we want to
2071+ // suggest replacing `'a` with `'static`.
2072+ let mut lifetimes = vec ! [ tcx. lifetimes. re_static] ;
2073+ lifetimes. extend (
2074+ ty:: GenericArgs :: identity_for_item ( tcx, owner_id) . iter ( ) . filter_map ( |arg| arg. as_region ( ) ) ,
2075+ ) ;
2076+ // If we are in a function, add its late-bound lifetimes too.
2077+ if matches ! ( def_kind, DefKind :: Fn | DefKind :: AssocFn ) {
2078+ for var in tcx. fn_sig ( owner_id) . instantiate_identity ( ) . bound_vars ( ) {
2079+ let ty:: BoundVariableKind :: Region ( kind) = var else { continue } ;
2080+ lifetimes. push ( ty:: Region :: new_late_param ( tcx, owner_id. to_def_id ( ) , kind) ) ;
2081+ }
2082+ }
2083+ lifetimes. retain ( |candidate| candidate. has_name ( ) ) ;
2084+
2085+ // Keep track of lifetimes which have already been replaced with other lifetimes.
2086+ // This makes sure that if `'a = 'b = 'c`, we don't say `'c` should be replaced by
2087+ // both `'a` and `'b`.
2088+ let mut shadowed = FxHashSet :: default ( ) ;
2089+
2090+ for ( idx, & candidate) in lifetimes. iter ( ) . enumerate ( ) {
2091+ // Don't suggest removing a lifetime twice.
2092+ if shadowed. contains ( & candidate) {
2093+ continue ;
2094+ }
2095+
2096+ for & victim in & lifetimes[ ( idx + 1 ) ..] {
2097+ // We only care about lifetimes that are "real", i.e. that have a def-id.
2098+ let ( ty:: ReEarlyParam ( ty:: EarlyParamRegion { def_id, .. } )
2099+ | ty:: ReLateParam ( ty:: LateParamRegion {
2100+ bound_region : ty:: BoundRegionKind :: BrNamed ( def_id, _) ,
2101+ ..
2102+ } ) ) = victim. kind ( )
2103+ else {
2104+ continue ;
2105+ } ;
2106+
2107+ // Do not rename lifetimes not local to this item since they'll overlap
2108+ // with the lint running on the parent. We still want to consider parent
2109+ // lifetimes which make child lifetimes redundant, otherwise we would
2110+ // have truncated the `identity_for_item` args above.
2111+ if tcx. parent ( def_id) != owner_id. to_def_id ( ) {
2112+ continue ;
2113+ }
2114+
2115+ // If there are no lifetime errors, then we have proven that `'candidate = 'victim`!
2116+ if outlives_env. free_region_map ( ) . sub_free_regions ( tcx, candidate, victim)
2117+ && outlives_env. free_region_map ( ) . sub_free_regions ( tcx, victim, candidate)
2118+ {
2119+ shadowed. insert ( victim) ;
2120+ tcx. emit_spanned_lint (
2121+ rustc_lint_defs:: builtin:: UNUSED_LIFETIMES ,
2122+ tcx. local_def_id_to_hir_id ( def_id. expect_local ( ) ) ,
2123+ tcx. def_span ( def_id) ,
2124+ RedundantLifetimeArgsLint { candidate, victim } ,
2125+ ) ;
2126+ }
2127+ }
2128+ }
2129+ }
2130+
2131+ #[ derive( LintDiagnostic ) ]
2132+ #[ diag( hir_analysis_redundant_lifetime_args) ]
2133+ #[ note]
2134+ struct RedundantLifetimeArgsLint < ' tcx > {
2135+ /// The lifetime we have found to be redundant.
2136+ victim : ty:: Region < ' tcx > ,
2137+ // The lifetime we can replace the victim with.
2138+ candidate : ty:: Region < ' tcx > ,
2139+ }
2140+
20132141pub fn provide ( providers : & mut Providers ) {
20142142 * providers = Providers { check_mod_type_wf, check_well_formed, ..* providers } ;
20152143}
0 commit comments