bon_macros/normalization/
self_ty.rs

1use crate::util::prelude::*;
2use syn::spanned::Spanned;
3use syn::visit_mut::VisitMut;
4
5pub(crate) struct NormalizeSelfTy<'a> {
6    pub(crate) self_ty: &'a syn::Type,
7}
8
9impl VisitMut for NormalizeSelfTy<'_> {
10    fn visit_item_mut(&mut self, _item: &mut syn::Item) {
11        // Don't recurse into nested items because `Self` isn't available there.
12    }
13
14    fn visit_receiver_mut(&mut self, _receiver: &mut syn::Receiver) {
15        // Don't recurse into the receiver. Keep it at `Self` as it was.
16        // We normalize `Self` at a later stage. This is to keep the code
17        // generated via `quote!()` using the simpler syntax of `self` without
18        // an explicit type annotation, which requires that receiver's type
19        // is left intact during normalization here.
20    }
21
22    fn visit_impl_item_fn_mut(&mut self, fn_item: &mut syn::ImplItemFn) {
23        // We are interested only in signatures of functions. Don't recurse
24        // into the function's block.
25        self.visit_signature_mut(&mut fn_item.sig);
26    }
27
28    // TODO: this isn't all. We need to replace `Self` references in const generics
29    // expressions as well.
30
31    fn visit_type_mut(&mut self, ty: &mut syn::Type) {
32        syn::visit_mut::visit_type_mut(self, ty);
33
34        let ty_path = match ty {
35            syn::Type::Path(ty_path) => ty_path,
36            _ => return,
37        };
38
39        if !ty_path.path.is_ident("Self") {
40            return;
41        }
42
43        *ty = (*self.self_ty).clone();
44    }
45
46    fn visit_type_path_mut(&mut self, type_path: &mut syn::TypePath) {
47        syn::visit_mut::visit_type_path_mut(self, type_path);
48
49        let syn::TypePath { qself, path } = type_path;
50
51        let is_self_projection =
52            qself.is_none() && path.starts_with_segment("Self") && path.segments.len() > 1;
53
54        if !is_self_projection {
55            return;
56        }
57
58        // There is no `.remove()` method in `Punctuated`
59        // https://github.com/dtolnay/syn/issues/1314
60        path.segments = std::mem::take(&mut path.segments)
61            .into_iter()
62            .skip(1)
63            .collect();
64
65        let span = type_path.span();
66
67        // QSelf doesn't implement `Parse` trait
68        type_path.qself = Some(syn::QSelf {
69            lt_token: syn::Token![<](span),
70            ty: Box::new(self.self_ty.clone()),
71            position: 0,
72            as_token: None,
73            gt_token: syn::Token![>](span),
74        });
75    }
76}