1 use super::ResolverAstLoweringExt;
2 use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
3 use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
4 use rustc_hir::def::LifetimeRes;
5 use rustc_middle::span_bug;
6 use rustc_middle::ty::ResolverAstLowering;
7 use rustc_span::symbol::{kw, Ident};
10 struct LifetimeCollectVisitor<'ast> {
11 resolver: &'ast ResolverAstLowering,
12 current_binders: Vec<NodeId>,
13 collected_lifetimes: Vec<Lifetime>,
16 impl<'ast> LifetimeCollectVisitor<'ast> {
17 fn new(resolver: &'ast ResolverAstLowering) -> Self {
18 Self { resolver, current_binders: Vec::new(), collected_lifetimes: Vec::new() }
21 fn record_lifetime_use(&mut self, lifetime: Lifetime) {
22 match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) {
23 LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => {
24 if !self.current_binders.contains(&binder) {
25 if !self.collected_lifetimes.contains(&lifetime) {
26 self.collected_lifetimes.push(lifetime);
30 LifetimeRes::Static | LifetimeRes::Error => {
31 if !self.collected_lifetimes.contains(&lifetime) {
32 self.collected_lifetimes.push(lifetime);
35 LifetimeRes::Infer => {}
37 let bug_msg = format!(
38 "Unexpected lifetime resolution {:?} for {:?} at {:?}",
39 res, lifetime.ident, lifetime.ident.span
41 span_bug!(lifetime.ident.span, "{}", bug_msg);
46 /// This collect lifetimes that are elided, for nodes like `Foo<T>` where there are no explicit
47 /// lifetime nodes. Is equivalent to having "pseudo" nodes introduced for each of the node ids
48 /// in the list start..end.
49 fn record_elided_anchor(&mut self, node_id: NodeId, span: Span) {
50 if let Some(LifetimeRes::ElidedAnchor { start, end }) =
51 self.resolver.get_lifetime_res(node_id)
54 let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) };
55 self.record_lifetime_use(lifetime);
61 impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
62 fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) {
63 self.record_lifetime_use(*lifetime);
66 fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) {
67 self.record_elided_anchor(path_segment.id, path_segment.ident.span);
68 visit::walk_path_segment(self, path_segment);
71 fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
72 self.current_binders.push(t.trait_ref.ref_id);
74 visit::walk_poly_trait_ref(self, t);
76 self.current_binders.pop();
79 fn visit_ty(&mut self, t: &'ast Ty) {
81 TyKind::BareFn(_) => {
82 self.current_binders.push(t.id);
83 visit::walk_ty(self, t);
84 self.current_binders.pop();
86 TyKind::Rptr(None, _) => {
87 self.record_elided_anchor(t.id, t.span);
88 visit::walk_ty(self, t);
91 visit::walk_ty(self, t);
97 pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> {
98 let mut visitor = LifetimeCollectVisitor::new(resolver);
99 visitor.visit_fn_ret_ty(ret_ty);
100 visitor.collected_lifetimes
103 pub fn lifetimes_in_bounds(
104 resolver: &ResolverAstLowering,
105 bounds: &GenericBounds,
107 let mut visitor = LifetimeCollectVisitor::new(resolver);
108 for bound in bounds {
109 visitor.visit_param_bound(bound, BoundKind::Bound);
111 visitor.collected_lifetimes