Skip to content

Commit 6654aab

Browse files
committed
Auto merge of rust-lang#97313 - cjgillot:ast-lifetimes-anon, r=petrochenkov
Resolve function lifetime elision on the AST ~Based on rust-lang#97720 Lifetime elision for functions is purely syntactic in nature, so can be resolved on the AST. This PR replicates the elision logic and diagnostics on the AST, and replaces HIR-based resolution by a `delay_span_bug`. This refactor allows for more consistent diagnostics, which don't have to guess the original code from HIR. r? `@petrochenkov`
2 parents 632f994 + 419d39c commit 6654aab

File tree

1 file changed

+46
-32
lines changed

1 file changed

+46
-32
lines changed

clippy_lints/src/lifetimes.rs

+46-32
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ use rustc_hir::intravisit::{
99
use rustc_hir::FnRetTy::Return;
1010
use rustc_hir::{
1111
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
12-
ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, LifetimeParamKind, ParamName, PolyTraitRef,
13-
PredicateOrigin, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
12+
ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin,
13+
TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
1414
};
1515
use rustc_lint::{LateContext, LateLintPass};
1616
use rustc_middle::hir::nested_filter as middle_nested_filter;
17+
use rustc_middle::ty::TyCtxt;
1718
use rustc_session::{declare_lint_pass, declare_tool_lint};
19+
use rustc_span::def_id::LocalDefId;
1820
use rustc_span::source_map::Span;
1921
use rustc_span::symbol::{kw, Ident, Symbol};
2022

@@ -129,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
129131
enum RefLt {
130132
Unnamed,
131133
Static,
132-
Named(Symbol),
134+
Named(LocalDefId),
133135
}
134136

135137
fn check_fn_inner<'tcx>(
@@ -232,7 +234,7 @@ fn could_use_elision<'tcx>(
232234
// level of the current item.
233235

234236
// check named LTs
235-
let allowed_lts = allowed_lts_from(named_generics);
237+
let allowed_lts = allowed_lts_from(cx.tcx, named_generics);
236238

237239
// these will collect all the lifetimes for references in arg/return types
238240
let mut input_visitor = RefVisitor::new(cx);
@@ -254,22 +256,6 @@ fn could_use_elision<'tcx>(
254256
return false;
255257
}
256258

257-
if allowed_lts
258-
.intersection(
259-
&input_visitor
260-
.nested_elision_site_lts
261-
.iter()
262-
.chain(output_visitor.nested_elision_site_lts.iter())
263-
.cloned()
264-
.filter(|v| matches!(v, RefLt::Named(_)))
265-
.collect(),
266-
)
267-
.next()
268-
.is_some()
269-
{
270-
return false;
271-
}
272-
273259
let input_lts = input_visitor.lts;
274260
let output_lts = output_visitor.lts;
275261

@@ -303,6 +289,31 @@ fn could_use_elision<'tcx>(
303289
}
304290
}
305291

292+
// check for higher-ranked trait bounds
293+
if !input_visitor.nested_elision_site_lts.is_empty() || !output_visitor.nested_elision_site_lts.is_empty() {
294+
let allowed_lts: FxHashSet<_> = allowed_lts
295+
.iter()
296+
.filter_map(|lt| match lt {
297+
RefLt::Named(def_id) => Some(cx.tcx.item_name(def_id.to_def_id())),
298+
_ => None,
299+
})
300+
.collect();
301+
for lt in input_visitor.nested_elision_site_lts {
302+
if let RefLt::Named(def_id) = lt {
303+
if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
304+
return false;
305+
}
306+
}
307+
}
308+
for lt in output_visitor.nested_elision_site_lts {
309+
if let RefLt::Named(def_id) = lt {
310+
if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
311+
return false;
312+
}
313+
}
314+
}
315+
}
316+
306317
// no input lifetimes? easy case!
307318
if input_lts.is_empty() {
308319
false
@@ -335,14 +346,11 @@ fn could_use_elision<'tcx>(
335346
}
336347
}
337348

338-
fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
349+
fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
339350
let mut allowed_lts = FxHashSet::default();
340351
for par in named_generics.iter() {
341-
if let GenericParamKind::Lifetime {
342-
kind: LifetimeParamKind::Explicit,
343-
} = par.kind
344-
{
345-
allowed_lts.insert(RefLt::Named(par.name.ident().name));
352+
if let GenericParamKind::Lifetime { .. } = par.kind {
353+
allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id)));
346354
}
347355
}
348356
allowed_lts.insert(RefLt::Unnamed);
@@ -385,8 +393,10 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
385393
self.lts.push(RefLt::Unnamed);
386394
} else if lt.is_elided() {
387395
self.lts.push(RefLt::Unnamed);
396+
} else if let LifetimeName::Param(def_id, _) = lt.name {
397+
self.lts.push(RefLt::Named(def_id));
388398
} else {
389-
self.lts.push(RefLt::Named(lt.name.ident().name));
399+
self.lts.push(RefLt::Unnamed);
390400
}
391401
} else {
392402
self.lts.push(RefLt::Unnamed);
@@ -434,10 +444,15 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
434444
TyKind::OpaqueDef(item, bounds) => {
435445
let map = self.cx.tcx.hir();
436446
let item = map.item(item);
447+
let len = self.lts.len();
437448
walk_item(self, item);
438-
walk_ty(self, ty);
449+
self.lts.truncate(len);
439450
self.lts.extend(bounds.iter().filter_map(|bound| match bound {
440-
GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
451+
GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id, _) = l.name {
452+
RefLt::Named(def_id)
453+
} else {
454+
RefLt::Unnamed
455+
}),
441456
_ => None,
442457
}));
443458
},
@@ -456,9 +471,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
456471
}
457472
return;
458473
},
459-
_ => (),
474+
_ => walk_ty(self, ty),
460475
}
461-
walk_ty(self, ty);
462476
}
463477
}
464478

@@ -477,7 +491,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
477491
return true;
478492
}
479493
// if the bounds define new lifetimes, they are fine to occur
480-
let allowed_lts = allowed_lts_from(pred.bound_generic_params);
494+
let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params);
481495
// now walk the bounds
482496
for bound in pred.bounds.iter() {
483497
walk_param_bound(&mut visitor, bound);

0 commit comments

Comments
 (0)