Skip to content

Commit fc44f8e

Browse files
Move check to wfcheck
1 parent 2ac5593 commit fc44f8e

10 files changed

+206
-197
lines changed

compiler/rustc_hir_analysis/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
350350
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
351351
.label = not allowed in type signatures
352352
353+
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
354+
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
355+
353356
hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`
354357
355358
hir_analysis_return_type_notation_equality_bound =

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+128
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ use rustc_ast as ast;
88
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
99
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
1010
use rustc_hir as hir;
11+
use rustc_hir::def::DefKind;
1112
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
1213
use rustc_hir::lang_items::LangItem;
1314
use rustc_hir::ItemKind;
1415
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
1516
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
17+
use rustc_macros::LintDiagnostic;
1618
use rustc_middle::query::Providers;
1719
use rustc_middle::ty::print::with_no_trimmed_paths;
1820
use 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+
check_for_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 check_for_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+
20132141
pub fn provide(providers: &mut Providers) {
20142142
*providers = Providers { check_mod_type_wf, check_well_formed, ..*providers };
20152143
}

compiler/rustc_lint/messages.ftl

-3
Original file line numberDiff line numberDiff line change
@@ -531,9 +531,6 @@ lint_reason_must_be_string_literal = reason must be a string literal
531531
532532
lint_reason_must_come_last = reason in lint attribute must come last
533533
534-
lint_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
535-
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
536-
537534
lint_redundant_semicolons =
538535
unnecessary trailing {$multiple ->
539536
[true] semicolons

compiler/rustc_lint/src/lib.rs

-3
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ mod opaque_hidden_inferred_bound;
7878
mod pass_by_value;
7979
mod passes;
8080
mod ptr_nulls;
81-
mod redundant_lifetime_args;
8281
mod redundant_semicolon;
8382
mod reference_casting;
8483
mod traits;
@@ -114,7 +113,6 @@ use noop_method_call::*;
114113
use opaque_hidden_inferred_bound::*;
115114
use pass_by_value::*;
116115
use ptr_nulls::*;
117-
use redundant_lifetime_args::RedundantLifetimeArgs;
118116
use redundant_semicolon::*;
119117
use reference_casting::*;
120118
use traits::*;
@@ -235,7 +233,6 @@ late_lint_methods!(
235233
MissingDoc: MissingDoc,
236234
AsyncFnInTrait: AsyncFnInTrait,
237235
NonLocalDefinitions: NonLocalDefinitions::default(),
238-
RedundantLifetimeArgs: RedundantLifetimeArgs,
239236
]
240237
]
241238
);

compiler/rustc_lint/src/redundant_lifetime_args.rs

-177
This file was deleted.

tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
#![warn(unused_lifetimes)]
2+
13
pub trait X {
2-
type Y<'a: 'static>;
4+
type Y<'a: 'static>; //~ WARN unnecessary lifetime parameter `'a`
35
}
46

57
impl X for () {

0 commit comments

Comments
 (0)