bon_macros/normalization/
lifetimes.rs
1use super::GenericsNamespace;
2use crate::util::prelude::*;
3use syn::visit::Visit;
4use syn::visit_mut::VisitMut;
5
6pub(crate) struct NormalizeLifetimes<'a> {
7 namespace: &'a GenericsNamespace,
8}
9
10impl<'a> NormalizeLifetimes<'a> {
11 pub(crate) fn new(namespace: &'a GenericsNamespace) -> Self {
12 Self { namespace }
13 }
14}
15
16impl VisitMut for NormalizeLifetimes<'_> {
17 fn visit_item_impl_mut(&mut self, impl_block: &mut syn::ItemImpl) {
18 for item in &mut impl_block.items {
19 self.visit_impl_item_mut(item);
20 }
21
22 AssignLifetimes::new(self, "i", &mut impl_block.generics)
23 .visit_type_mut(&mut impl_block.self_ty);
24 }
25
26 fn visit_impl_item_mut(&mut self, item: &mut syn::ImplItem) {
27 if let syn::ImplItem::Fn(fn_item) = item {
28 self.visit_signature_mut(&mut fn_item.sig);
29 }
30 }
31
32 fn visit_item_fn_mut(&mut self, fn_item: &mut syn::ItemFn) {
33 self.visit_signature_mut(&mut fn_item.sig);
34 }
35
36 fn visit_signature_mut(&mut self, signature: &mut syn::Signature) {
37 let mut visitor = AssignLifetimes::new(self, "f", &mut signature.generics);
38 for arg in &mut signature.inputs {
39 visitor.visit_fn_arg_mut(arg);
40 }
41
42 let return_type = match &mut signature.output {
43 syn::ReturnType::Type(_, return_type) => return_type,
44 syn::ReturnType::Default => return,
45 };
46
47 let elided_output_lifetime = signature
52 .inputs
53 .first()
54 .and_then(|arg| {
55 let receiver = arg.as_receiver()?;
56 receiver.lifetime().or_else(|| match receiver.ty.as_ref() {
57 syn::Type::Reference(reference) => reference.lifetime.as_ref(),
58 _ => None,
59 })
60 })
61 .or_else(|| {
62 let lifetime = signature
63 .inputs
64 .iter()
65 .filter_map(syn::FnArg::as_typed)
66 .fold(LifetimeCollector::None, |mut acc, pat_type| {
67 acc.visit_pat_type(pat_type);
68 acc
69 });
70
71 match lifetime {
72 LifetimeCollector::Single(lifetime) => Some(lifetime),
73 _ => None,
74 }
75 });
76
77 let elided_lifetime = match elided_output_lifetime {
78 Some(elided_lifetime) => elided_lifetime,
79 _ => return,
80 };
81
82 ElideOutputLifetime { elided_lifetime }.visit_type_mut(return_type);
83 }
84}
85
86struct AssignLifetimes<'a> {
87 base: &'a NormalizeLifetimes<'a>,
88
89 prefix: &'static str,
90
91 generics: &'a mut syn::Generics,
93
94 next_lifetime_index: usize,
95}
96
97impl<'a> AssignLifetimes<'a> {
98 fn new(
99 base: &'a NormalizeLifetimes<'a>,
100 prefix: &'static str,
101 generics: &'a mut syn::Generics,
102 ) -> Self {
103 Self {
104 base,
105 prefix,
106 generics,
107 next_lifetime_index: 1,
108 }
109 }
110}
111
112impl VisitMut for AssignLifetimes<'_> {
113 fn visit_item_mut(&mut self, _item: &mut syn::Item) {
114 }
116
117 fn visit_type_bare_fn_mut(&mut self, _bare_fn: &mut syn::TypeBareFn) {
118 }
121
122 fn visit_parenthesized_generic_arguments_mut(
123 &mut self,
124 _args: &mut syn::ParenthesizedGenericArguments,
125 ) {
126 }
128
129 fn visit_lifetime_mut(&mut self, lifetime: &mut syn::Lifetime) {
130 if lifetime.ident == "_" {
131 *lifetime = self.next_lifetime();
132 }
133 }
134
135 fn visit_type_reference_mut(&mut self, reference: &mut syn::TypeReference) {
136 syn::visit_mut::visit_type_reference_mut(self, reference);
137 reference
138 .lifetime
139 .get_or_insert_with(|| self.next_lifetime());
140 }
141
142 fn visit_receiver_mut(&mut self, receiver: &mut syn::Receiver) {
143 if receiver.colon_token.is_some() {
146 syn::visit_mut::visit_type_mut(self, &mut receiver.ty);
147 return;
148 }
149
150 let lifetime = match &mut receiver.reference {
151 Some((_and, lifetime)) => lifetime,
152 _ => return,
153 };
154
155 if matches!(lifetime, Some(lifetime) if lifetime.ident != "_") {
156 return;
157 }
158
159 let receiver_ty = match receiver.ty.as_mut() {
160 syn::Type::Reference(receiver_ty) => receiver_ty,
161 _ => return,
162 };
163
164 let new_lifetime = self.next_lifetime();
165
166 *lifetime = Some(new_lifetime.clone());
167
168 receiver_ty.lifetime = Some(new_lifetime);
169 }
170}
171
172impl AssignLifetimes<'_> {
173 fn next_lifetime(&mut self) -> syn::Lifetime {
177 let index = self.next_lifetime_index;
178 self.next_lifetime_index += 1;
179
180 let mut lifetime = self
181 .base
182 .namespace
183 .unique_lifetime(format!("{}{index}", self.prefix));
184
185 lifetime.insert(0, '\'');
188
189 let lifetime = syn::Lifetime::new(&lifetime, Span::call_site());
190
191 let lifetime_param = syn::LifetimeParam::new(lifetime.clone());
192 let lifetime_param = syn::GenericParam::Lifetime(lifetime_param);
193 self.generics.params.insert(index - 1, lifetime_param);
194
195 lifetime
196 }
197}
198
199enum LifetimeCollector<'a> {
200 None,
201 Single(&'a syn::Lifetime),
202 Multiple,
203}
204
205impl<'a> Visit<'a> for LifetimeCollector<'a> {
206 fn visit_item(&mut self, _item: &syn::Item) {
207 }
209
210 fn visit_type_bare_fn(&mut self, _bare_fn: &syn::TypeBareFn) {
211 }
214
215 fn visit_parenthesized_generic_arguments(
216 &mut self,
217 _args: &syn::ParenthesizedGenericArguments,
218 ) {
219 }
221
222 fn visit_lifetime(&mut self, lifetime: &'a syn::Lifetime) {
223 match self {
224 Self::None => *self = Self::Single(lifetime),
225 Self::Single(_) => *self = Self::Multiple,
226 Self::Multiple => {}
227 }
228 }
229}
230
231struct ElideOutputLifetime<'a> {
232 elided_lifetime: &'a syn::Lifetime,
233}
234
235impl VisitMut for ElideOutputLifetime<'_> {
236 fn visit_item_mut(&mut self, _item: &mut syn::Item) {
237 }
239
240 fn visit_type_bare_fn_mut(&mut self, _bare_fn: &mut syn::TypeBareFn) {
241 }
244
245 fn visit_parenthesized_generic_arguments_mut(
246 &mut self,
247 _args: &mut syn::ParenthesizedGenericArguments,
248 ) {
249 }
251
252 fn visit_lifetime_mut(&mut self, lifetime: &mut syn::Lifetime) {
253 if lifetime.ident == "_" {
254 *lifetime = self.elided_lifetime.clone();
255 }
256 }
257
258 fn visit_type_reference_mut(&mut self, reference: &mut syn::TypeReference) {
259 syn::visit_mut::visit_type_reference_mut(self, reference);
260
261 reference
262 .lifetime
263 .get_or_insert_with(|| self.elided_lifetime.clone());
264 }
265}