@@ -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,137 @@ 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 : _ } => {
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 associated items of trait
2038+ // implementations, since the signature is required to be compatible
2039+ // with the trait, even if the implementation implies some lifetimes
2040+ // are redundant.
2041+ return ;
2042+ }
2043+ }
2044+ DefKind :: Mod
2045+ | DefKind :: Variant
2046+ | DefKind :: TyAlias
2047+ | DefKind :: ForeignTy
2048+ | DefKind :: TyParam
2049+ | DefKind :: ConstParam
2050+ | DefKind :: Static { .. }
2051+ | DefKind :: Ctor ( _, _)
2052+ | DefKind :: Macro ( _)
2053+ | DefKind :: ExternCrate
2054+ | DefKind :: Use
2055+ | DefKind :: ForeignMod
2056+ | DefKind :: AnonConst
2057+ | DefKind :: InlineConst
2058+ | DefKind :: OpaqueTy
2059+ | DefKind :: Field
2060+ | DefKind :: LifetimeParam
2061+ | DefKind :: GlobalAsm
2062+ | DefKind :: Closure => return ,
2063+ }
2064+
2065+ // The ordering of this lifetime map is a bit subtle.
2066+ //
2067+ // Specifically, we want to find a "candidate" lifetime that precedes a "victim" lifetime,
2068+ // where we can prove that `'candidate = 'victim`.
2069+ //
2070+ // `'static` must come first in this list because we can never replace `'static` with
2071+ // something else, but if we find some lifetime `'a` where `'a = 'static`, we want to
2072+ // suggest replacing `'a` with `'static`.
2073+ let mut lifetimes = vec ! [ tcx. lifetimes. re_static] ;
2074+ lifetimes. extend (
2075+ ty:: GenericArgs :: identity_for_item ( tcx, owner_id) . iter ( ) . filter_map ( |arg| arg. as_region ( ) ) ,
2076+ ) ;
2077+ // If we are in a function, add its late-bound lifetimes too.
2078+ if matches ! ( def_kind, DefKind :: Fn | DefKind :: AssocFn ) {
2079+ for var in tcx. fn_sig ( owner_id) . instantiate_identity ( ) . bound_vars ( ) {
2080+ let ty:: BoundVariableKind :: Region ( kind) = var else { continue } ;
2081+ lifetimes. push ( ty:: Region :: new_late_param ( tcx, owner_id. to_def_id ( ) , kind) ) ;
2082+ }
2083+ }
2084+ lifetimes. retain ( |candidate| candidate. has_name ( ) ) ;
2085+
2086+ // Keep track of lifetimes which have already been replaced with other lifetimes.
2087+ // This makes sure that if `'a = 'b = 'c`, we don't say `'c` should be replaced by
2088+ // both `'a` and `'b`.
2089+ let mut shadowed = FxHashSet :: default ( ) ;
2090+
2091+ for ( idx, & candidate) in lifetimes. iter ( ) . enumerate ( ) {
2092+ // Don't suggest removing a lifetime twice. We only need to check this
2093+ // here and not up in the `victim` loop because equality is transitive,
2094+ // so if A = C and B = C, then A must = B, so it'll be shadowed too in
2095+ // A's victim loop.
2096+ if shadowed. contains ( & candidate) {
2097+ continue ;
2098+ }
2099+
2100+ for & victim in & lifetimes[ ( idx + 1 ) ..] {
2101+ // We should only have late-bound lifetimes of the `BrNamed` variety,
2102+ // since we get these signatures straight from `hir_lowering`. And any
2103+ // other regions (ReError/ReStatic/etc.) shouldn't matter, since we
2104+ // can't really suggest to remove them.
2105+ let ( ty:: ReEarlyParam ( ty:: EarlyParamRegion { def_id, .. } )
2106+ | ty:: ReLateParam ( ty:: LateParamRegion {
2107+ bound_region : ty:: BoundRegionKind :: BrNamed ( def_id, _) ,
2108+ ..
2109+ } ) ) = victim. kind ( )
2110+ else {
2111+ continue ;
2112+ } ;
2113+
2114+ // Do not rename lifetimes not local to this item since they'll overlap
2115+ // with the lint running on the parent. We still want to consider parent
2116+ // lifetimes which make child lifetimes redundant, otherwise we would
2117+ // have truncated the `identity_for_item` args above.
2118+ if tcx. parent ( def_id) != owner_id. to_def_id ( ) {
2119+ continue ;
2120+ }
2121+
2122+ // If `candidate <: victim` and `victim <: candidate`, then they're equal.
2123+ if outlives_env. free_region_map ( ) . sub_free_regions ( tcx, candidate, victim)
2124+ && outlives_env. free_region_map ( ) . sub_free_regions ( tcx, victim, candidate)
2125+ {
2126+ shadowed. insert ( victim) ;
2127+ tcx. emit_node_span_lint (
2128+ rustc_lint_defs:: builtin:: REDUNDANT_LIFETIMES ,
2129+ tcx. local_def_id_to_hir_id ( def_id. expect_local ( ) ) ,
2130+ tcx. def_span ( def_id) ,
2131+ RedundantLifetimeArgsLint { candidate, victim } ,
2132+ ) ;
2133+ }
2134+ }
2135+ }
2136+ }
2137+
2138+ #[ derive( LintDiagnostic ) ]
2139+ #[ diag( hir_analysis_redundant_lifetime_args) ]
2140+ #[ note]
2141+ struct RedundantLifetimeArgsLint < ' tcx > {
2142+ /// The lifetime we have found to be redundant.
2143+ victim : ty:: Region < ' tcx > ,
2144+ // The lifetime we can replace the victim with.
2145+ candidate : ty:: Region < ' tcx > ,
2146+ }
2147+
20132148pub fn provide ( providers : & mut Providers ) {
20142149 * providers = Providers { check_mod_type_wf, check_well_formed, ..* providers } ;
20152150}
0 commit comments