| 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(&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 | |