1 | use proc_macro2::{Span, TokenStream}; |
2 | use std::mem; |
3 | use syn::visit_mut::{self, VisitMut}; |
4 | use syn::{ |
5 | parse_quote_spanned, token, Expr, GenericArgument, Lifetime, Receiver, ReturnType, Token, Type, |
6 | TypeBareFn, TypeImplTrait, TypeParen, TypePtr, TypeReference, |
7 | }; |
8 | |
9 | pub struct CollectLifetimes { |
10 | pub elided: Vec<Lifetime>, |
11 | pub explicit: Vec<Lifetime>, |
12 | } |
13 | |
14 | impl CollectLifetimes { |
15 | pub fn new() -> Self { |
16 | CollectLifetimes { |
17 | elided: Vec::new(), |
18 | explicit: Vec::new(), |
19 | } |
20 | } |
21 | |
22 | fn visit_opt_lifetime(&mut self, reference: Token![&], lifetime: &mut Option<Lifetime>) { |
23 | match lifetime { |
24 | None => *lifetime = Some(self.next_lifetime(reference.span)), |
25 | Some(lifetime) => self.visit_lifetime(lifetime), |
26 | } |
27 | } |
28 | |
29 | fn visit_lifetime(&mut self, lifetime: &mut Lifetime) { |
30 | if lifetime.ident == "_" { |
31 | *lifetime = self.next_lifetime(lifetime.span()); |
32 | } else { |
33 | self.explicit.push(lifetime.clone()); |
34 | } |
35 | } |
36 | |
37 | fn next_lifetime(&mut self, span: Span) -> Lifetime { |
38 | let name = format!("'life {}" , self.elided.len()); |
39 | let life = Lifetime::new(&name, span); |
40 | self.elided.push(life.clone()); |
41 | life |
42 | } |
43 | } |
44 | |
45 | impl VisitMut for CollectLifetimes { |
46 | fn visit_receiver_mut(&mut self, arg: &mut Receiver) { |
47 | if let Some((reference: &mut And, lifetime: &mut Option)) = &mut arg.reference { |
48 | self.visit_opt_lifetime(*reference, lifetime); |
49 | } else { |
50 | visit_mut::visit_type_mut(self, &mut arg.ty); |
51 | } |
52 | } |
53 | |
54 | fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) { |
55 | self.visit_opt_lifetime(reference:ty.and_token, &mut ty.lifetime); |
56 | visit_mut::visit_type_reference_mut(self, node:ty); |
57 | } |
58 | |
59 | fn visit_generic_argument_mut(&mut self, gen: &mut GenericArgument) { |
60 | if let GenericArgument::Lifetime(lifetime: &mut Lifetime) = gen { |
61 | self.visit_lifetime(lifetime); |
62 | } |
63 | visit_mut::visit_generic_argument_mut(self, node:gen); |
64 | } |
65 | } |
66 | |
67 | pub struct AddLifetimeToImplTrait; |
68 | |
69 | impl VisitMut for AddLifetimeToImplTrait { |
70 | fn visit_type_impl_trait_mut(&mut self, ty: &mut TypeImplTrait) { |
71 | let span = ty.impl_token.span; |
72 | let lifetime = parse_quote_spanned!(span=> 'async_trait); |
73 | ty.bounds.insert(0, lifetime); |
74 | if let Some(punct) = ty.bounds.pairs_mut().next().unwrap().punct_mut() { |
75 | punct.span = span; |
76 | } |
77 | visit_mut::visit_type_impl_trait_mut(self, ty); |
78 | } |
79 | |
80 | fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) { |
81 | parenthesize_impl_trait(&mut ty.elem, ty.and_token.span); |
82 | visit_mut::visit_type_reference_mut(self, ty); |
83 | } |
84 | |
85 | fn visit_type_ptr_mut(&mut self, ty: &mut TypePtr) { |
86 | parenthesize_impl_trait(&mut ty.elem, ty.star_token.span); |
87 | visit_mut::visit_type_ptr_mut(self, ty); |
88 | } |
89 | |
90 | fn visit_type_bare_fn_mut(&mut self, ty: &mut TypeBareFn) { |
91 | if let ReturnType::Type(arrow, return_type) = &mut ty.output { |
92 | parenthesize_impl_trait(return_type, arrow.spans[0]); |
93 | } |
94 | visit_mut::visit_type_bare_fn_mut(self, ty); |
95 | } |
96 | |
97 | fn visit_expr_mut(&mut self, _e: &mut Expr) { |
98 | // Do not recurse into impl Traits inside of an array length expression. |
99 | // |
100 | // fn outer(arg: [u8; { fn inner(_: impl Trait) {}; 0 }]); |
101 | } |
102 | } |
103 | |
104 | fn parenthesize_impl_trait(elem: &mut Type, paren_span: Span) { |
105 | if let Type::ImplTrait(_) = *elem { |
106 | let placeholder: Type = Type::Verbatim(TokenStream::new()); |
107 | *elem = Type::Paren(TypeParen { |
108 | paren_token: token::Paren(paren_span), |
109 | elem: Box::new(mem::replace(dest:elem, src:placeholder)), |
110 | }); |
111 | } |
112 | } |
113 | |