]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_ast_lowering/src/lifetime_collector.rs
New upstream version 1.65.0+dfsg1
[rustc.git] / compiler / rustc_ast_lowering / src / lifetime_collector.rs
CommitLineData
064997fb
FG
1use super::ResolverAstLoweringExt;
2use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
f2b60f7d 3use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
064997fb
FG
4use rustc_hir::def::LifetimeRes;
5use rustc_middle::span_bug;
6use rustc_middle::ty::ResolverAstLowering;
7use rustc_span::symbol::{kw, Ident};
8use rustc_span::Span;
9
10struct LifetimeCollectVisitor<'ast> {
11 resolver: &'ast ResolverAstLowering,
12 current_binders: Vec<NodeId>,
13 collected_lifetimes: Vec<Lifetime>,
14}
15
16impl<'ast> LifetimeCollectVisitor<'ast> {
17 fn new(resolver: &'ast ResolverAstLowering) -> Self {
18 Self { resolver, current_binders: Vec::new(), collected_lifetimes: Vec::new() }
19 }
20
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);
27 }
28 }
29 }
30 LifetimeRes::Static | LifetimeRes::Error => {
31 if !self.collected_lifetimes.contains(&lifetime) {
32 self.collected_lifetimes.push(lifetime);
33 }
34 }
35 LifetimeRes::Infer => {}
36 res => {
37 let bug_msg = format!(
38 "Unexpected lifetime resolution {:?} for {:?} at {:?}",
39 res, lifetime.ident, lifetime.ident.span
40 );
41 span_bug!(lifetime.ident.span, "{}", bug_msg);
42 }
43 }
44 }
45
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)
52 {
53 for i in start..end {
54 let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) };
55 self.record_lifetime_use(lifetime);
56 }
57 }
58 }
59}
60
61impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
62 fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) {
63 self.record_lifetime_use(*lifetime);
64 }
65
f2b60f7d
FG
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);
064997fb
FG
69 }
70
f2b60f7d 71 fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
064997fb
FG
72 self.current_binders.push(t.trait_ref.ref_id);
73
f2b60f7d 74 visit::walk_poly_trait_ref(self, t);
064997fb
FG
75
76 self.current_binders.pop();
77 }
78
79 fn visit_ty(&mut self, t: &'ast Ty) {
80 match t.kind {
81 TyKind::BareFn(_) => {
82 self.current_binders.push(t.id);
83 visit::walk_ty(self, t);
84 self.current_binders.pop();
85 }
86 TyKind::Rptr(None, _) => {
87 self.record_elided_anchor(t.id, t.span);
88 visit::walk_ty(self, t);
89 }
90 _ => {
91 visit::walk_ty(self, t);
92 }
93 }
94 }
95}
96
97pub 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
101}
102
103pub fn lifetimes_in_bounds(
104 resolver: &ResolverAstLowering,
105 bounds: &GenericBounds,
106) -> Vec<Lifetime> {
107 let mut visitor = LifetimeCollectVisitor::new(resolver);
108 for bound in bounds {
109 visitor.visit_param_bound(bound, BoundKind::Bound);
110 }
111 visitor.collected_lifetimes
112}