Auto merge of #97313 - cjgillot:ast-lifetimes-anon, r=petrochenkov
Resolve function lifetime elision on the AST ~Based on https://github.com/rust-lang/rust/pull/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`
This commit is contained in:
commit
6654aabb0f
@ -9,12 +9,14 @@
|
|||||||
use rustc_hir::FnRetTy::Return;
|
use rustc_hir::FnRetTy::Return;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
|
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
|
||||||
ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, LifetimeParamKind, ParamName, PolyTraitRef,
|
ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin,
|
||||||
PredicateOrigin, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
|
TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::hir::nested_filter as middle_nested_filter;
|
use rustc_middle::hir::nested_filter as middle_nested_filter;
|
||||||
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::source_map::Span;
|
use rustc_span::source_map::Span;
|
||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||||
|
|
||||||
@ -129,7 +131,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
|
|||||||
enum RefLt {
|
enum RefLt {
|
||||||
Unnamed,
|
Unnamed,
|
||||||
Static,
|
Static,
|
||||||
Named(Symbol),
|
Named(LocalDefId),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_fn_inner<'tcx>(
|
fn check_fn_inner<'tcx>(
|
||||||
@ -232,7 +234,7 @@ fn could_use_elision<'tcx>(
|
|||||||
// level of the current item.
|
// level of the current item.
|
||||||
|
|
||||||
// check named LTs
|
// check named LTs
|
||||||
let allowed_lts = allowed_lts_from(named_generics);
|
let allowed_lts = allowed_lts_from(cx.tcx, named_generics);
|
||||||
|
|
||||||
// these will collect all the lifetimes for references in arg/return types
|
// these will collect all the lifetimes for references in arg/return types
|
||||||
let mut input_visitor = RefVisitor::new(cx);
|
let mut input_visitor = RefVisitor::new(cx);
|
||||||
@ -254,22 +256,6 @@ fn could_use_elision<'tcx>(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if allowed_lts
|
|
||||||
.intersection(
|
|
||||||
&input_visitor
|
|
||||||
.nested_elision_site_lts
|
|
||||||
.iter()
|
|
||||||
.chain(output_visitor.nested_elision_site_lts.iter())
|
|
||||||
.cloned()
|
|
||||||
.filter(|v| matches!(v, RefLt::Named(_)))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
.next()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let input_lts = input_visitor.lts;
|
let input_lts = input_visitor.lts;
|
||||||
let output_lts = output_visitor.lts;
|
let output_lts = output_visitor.lts;
|
||||||
|
|
||||||
@ -303,6 +289,31 @@ fn could_use_elision<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for higher-ranked trait bounds
|
||||||
|
if !input_visitor.nested_elision_site_lts.is_empty() || !output_visitor.nested_elision_site_lts.is_empty() {
|
||||||
|
let allowed_lts: FxHashSet<_> = allowed_lts
|
||||||
|
.iter()
|
||||||
|
.filter_map(|lt| match lt {
|
||||||
|
RefLt::Named(def_id) => Some(cx.tcx.item_name(def_id.to_def_id())),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
for lt in input_visitor.nested_elision_site_lts {
|
||||||
|
if let RefLt::Named(def_id) = lt {
|
||||||
|
if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for lt in output_visitor.nested_elision_site_lts {
|
||||||
|
if let RefLt::Named(def_id) = lt {
|
||||||
|
if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// no input lifetimes? easy case!
|
// no input lifetimes? easy case!
|
||||||
if input_lts.is_empty() {
|
if input_lts.is_empty() {
|
||||||
false
|
false
|
||||||
@ -335,14 +346,11 @@ fn could_use_elision<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
|
fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
|
||||||
let mut allowed_lts = FxHashSet::default();
|
let mut allowed_lts = FxHashSet::default();
|
||||||
for par in named_generics.iter() {
|
for par in named_generics.iter() {
|
||||||
if let GenericParamKind::Lifetime {
|
if let GenericParamKind::Lifetime { .. } = par.kind {
|
||||||
kind: LifetimeParamKind::Explicit,
|
allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id)));
|
||||||
} = par.kind
|
|
||||||
{
|
|
||||||
allowed_lts.insert(RefLt::Named(par.name.ident().name));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allowed_lts.insert(RefLt::Unnamed);
|
allowed_lts.insert(RefLt::Unnamed);
|
||||||
@ -385,8 +393,10 @@ fn record(&mut self, lifetime: &Option<Lifetime>) {
|
|||||||
self.lts.push(RefLt::Unnamed);
|
self.lts.push(RefLt::Unnamed);
|
||||||
} else if lt.is_elided() {
|
} else if lt.is_elided() {
|
||||||
self.lts.push(RefLt::Unnamed);
|
self.lts.push(RefLt::Unnamed);
|
||||||
|
} else if let LifetimeName::Param(def_id, _) = lt.name {
|
||||||
|
self.lts.push(RefLt::Named(def_id));
|
||||||
} else {
|
} else {
|
||||||
self.lts.push(RefLt::Named(lt.name.ident().name));
|
self.lts.push(RefLt::Unnamed);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.lts.push(RefLt::Unnamed);
|
self.lts.push(RefLt::Unnamed);
|
||||||
@ -434,10 +444,15 @@ fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
|
|||||||
TyKind::OpaqueDef(item, bounds) => {
|
TyKind::OpaqueDef(item, bounds) => {
|
||||||
let map = self.cx.tcx.hir();
|
let map = self.cx.tcx.hir();
|
||||||
let item = map.item(item);
|
let item = map.item(item);
|
||||||
|
let len = self.lts.len();
|
||||||
walk_item(self, item);
|
walk_item(self, item);
|
||||||
walk_ty(self, ty);
|
self.lts.truncate(len);
|
||||||
self.lts.extend(bounds.iter().filter_map(|bound| match bound {
|
self.lts.extend(bounds.iter().filter_map(|bound| match bound {
|
||||||
GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
|
GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id, _) = l.name {
|
||||||
|
RefLt::Named(def_id)
|
||||||
|
} else {
|
||||||
|
RefLt::Unnamed
|
||||||
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
@ -456,9 +471,8 @@ fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => walk_ty(self, ty),
|
||||||
}
|
}
|
||||||
walk_ty(self, ty);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,7 +491,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// if the bounds define new lifetimes, they are fine to occur
|
// if the bounds define new lifetimes, they are fine to occur
|
||||||
let allowed_lts = allowed_lts_from(pred.bound_generic_params);
|
let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params);
|
||||||
// now walk the bounds
|
// now walk the bounds
|
||||||
for bound in pred.bounds.iter() {
|
for bound in pred.bounds.iter() {
|
||||||
walk_param_bound(&mut visitor, bound);
|
walk_param_bound(&mut visitor, bound);
|
||||||
|
Loading…
Reference in New Issue
Block a user