forked from yewstack/yew
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lifetime.rs
135 lines (111 loc) · 4.15 KB
/
lifetime.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use proc_macro2::Span;
use std::sync::{Arc, Mutex};
use syn::visit_mut::{self, VisitMut};
use syn::{
GenericArgument, Lifetime, ParenthesizedGenericArguments, Receiver, TypeBareFn, TypeImplTrait,
TypeParamBound, TypeReference, TypeTraitObject,
};
// borrowed from the awesome async-trait crate.
pub struct CollectLifetimes {
pub elided: Vec<Lifetime>,
pub explicit: Vec<Lifetime>,
pub name: &'static str,
pub default_span: Span,
pub type_trait_obj_lock: Arc<Mutex<()>>,
pub impl_trait_lock: Arc<Mutex<()>>,
pub impl_fn_lock: Arc<Mutex<()>>,
}
impl CollectLifetimes {
pub fn new(name: &'static str, default_span: Span) -> Self {
CollectLifetimes {
elided: Vec::new(),
explicit: Vec::new(),
name,
default_span,
impl_trait_lock: Arc::default(),
type_trait_obj_lock: Arc::default(),
impl_fn_lock: Arc::default(),
}
}
fn is_impl_trait(&self) -> bool {
self.impl_trait_lock.try_lock().is_err()
}
fn is_type_trait_obj(&self) -> bool {
self.type_trait_obj_lock.try_lock().is_err()
}
fn is_impl_fn(&self) -> bool {
self.impl_fn_lock.try_lock().is_err()
}
fn visit_opt_lifetime(&mut self, lifetime: &mut Option<Lifetime>) {
match lifetime {
None => *lifetime = Some(self.next_lifetime(None)),
Some(lifetime) => self.visit_lifetime(lifetime),
}
}
fn visit_lifetime(&mut self, lifetime: &mut Lifetime) {
if lifetime.ident == "_" {
*lifetime = self.next_lifetime(lifetime.span());
} else {
self.explicit.push(lifetime.clone());
}
}
fn next_lifetime<S: Into<Option<Span>>>(&mut self, span: S) -> Lifetime {
let name = format!("{}{}", self.name, self.elided.len());
let span = span.into().unwrap_or(self.default_span);
let life = Lifetime::new(&name, span);
self.elided.push(life.clone());
life
}
}
impl VisitMut for CollectLifetimes {
fn visit_receiver_mut(&mut self, arg: &mut Receiver) {
if let Some((_, lifetime)) = &mut arg.reference {
self.visit_opt_lifetime(lifetime);
}
}
fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) {
// We don't rewrite references in the impl FnOnce(&arg) or fn(&arg)
if self.is_impl_fn() {
return;
}
self.visit_opt_lifetime(&mut ty.lifetime);
visit_mut::visit_type_reference_mut(self, ty);
}
fn visit_generic_argument_mut(&mut self, gen: &mut GenericArgument) {
// We don't rewrite types in the impl FnOnce(&arg) -> Type<'_>
if self.is_impl_fn() {
return;
}
if let GenericArgument::Lifetime(lifetime) = gen {
self.visit_lifetime(lifetime);
}
visit_mut::visit_generic_argument_mut(self, gen);
}
fn visit_type_impl_trait_mut(&mut self, impl_trait: &mut TypeImplTrait) {
let impl_trait_lock = self.impl_trait_lock.clone();
let _locked = impl_trait_lock.try_lock();
impl_trait
.bounds
.insert(0, TypeParamBound::Lifetime(self.next_lifetime(None)));
visit_mut::visit_type_impl_trait_mut(self, impl_trait);
}
fn visit_type_trait_object_mut(&mut self, type_trait_obj: &mut TypeTraitObject) {
let type_trait_obj_lock = self.type_trait_obj_lock.clone();
let _locked = type_trait_obj_lock.try_lock();
visit_mut::visit_type_trait_object_mut(self, type_trait_obj);
}
fn visit_parenthesized_generic_arguments_mut(
&mut self,
generic_args: &mut ParenthesizedGenericArguments,
) {
let impl_fn_lock = self.impl_fn_lock.clone();
let _maybe_locked =
(self.is_impl_trait() || self.is_type_trait_obj()).then(|| impl_fn_lock.try_lock());
visit_mut::visit_parenthesized_generic_arguments_mut(self, generic_args);
}
fn visit_type_bare_fn_mut(&mut self, i: &mut TypeBareFn) {
let impl_fn_lock = self.impl_fn_lock.clone();
let _locked = impl_fn_lock.try_lock();
visit_mut::visit_type_bare_fn_mut(self, i);
}
}