]>
Commit | Line | Data |
---|---|---|
064997fb FG |
1 | use super::ResolverAstLoweringExt; |
2 | use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; | |
f2b60f7d | 3 | use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; |
064997fb FG |
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}; | |
8 | use rustc_span::Span; | |
9 | ||
10 | struct LifetimeCollectVisitor<'ast> { | |
11 | resolver: &'ast ResolverAstLowering, | |
12 | current_binders: Vec<NodeId>, | |
13 | collected_lifetimes: Vec<Lifetime>, | |
14 | } | |
15 | ||
16 | impl<'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 | ||
61 | impl<'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 | } | |
f25598a0 | 86 | TyKind::Ref(None, _) => { |
064997fb FG |
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 | ||
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 | |
101 | } | |
102 | ||
103 | pub 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 | } |