Skip to main content

miniextendr_macros/miniextendr_impl_trait/
defaults.rs

1//! Instantiate omitted default-method signatures for concrete trait wrappers.
2
3use std::collections::HashMap;
4
5use syn::visit_mut::VisitMut;
6
7/// Default bodies stay on the trait. These synthetic impl methods are consumed
8/// only by wrapper/shim generation, never emitted as Rust overrides.
9pub(super) fn inherited_methods(
10    implementation: &syn::ItemImpl,
11    declaration: &[syn::TraitItemFn],
12    generics: &syn::Generics,
13    trait_path: &syn::Path,
14) -> syn::Result<Vec<syn::ImplItemFn>> {
15    let missing: Vec<_> = declaration
16        .iter()
17        .filter(|method| {
18            method.default.is_some()
19                && !implementation.items.iter().any(|item| {
20                    #[allow(non_exhaustive_omitted_patterns)] match item {
    syn::ImplItem::Fn(own) if own.sig.ident == method.sig.ident => true,
    _ => false,
}matches!(item, syn::ImplItem::Fn(own) if own.sig.ident == method.sig.ident)
21                })
22        })
23        .collect();
24    if missing.is_empty() {
25        return Ok(Vec::new());
26    }
27
28    let mut arguments = Substitution::new(generics, trait_path)?;
29    arguments.self_type = Some((*implementation.self_ty).clone());
30    arguments.trait_path = Some(trait_path.clone());
31    missing
32        .into_iter()
33        .map(|method| {
34            let mut sig = method.sig.clone();
35            arguments.visit_signature_mut(&mut sig);
36            let attrs = &method.attrs;
37            syn::parse2({
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut attrs, i) = attrs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let attrs =
                match attrs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&attrs, &mut _s);
        }
    }
    ::quote::ToTokens::to_tokens(&sig, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        ::quote::__private::TokenStream::new());
    _s
}quote::quote! { #(#attrs)* #sig {} })
38        })
39        .collect()
40}
41
42#[derive(#[automatically_derived]
impl ::core::default::Default for Substitution {
    #[inline]
    fn default() -> Self {
        Substitution {
            types: ::core::default::Default::default(),
            consts: ::core::default::Default::default(),
            lifetimes: ::core::default::Default::default(),
            self_type: ::core::default::Default::default(),
            trait_path: ::core::default::Default::default(),
        }
    }
}Default)]
43struct Substitution {
44    types: HashMap<syn::Ident, syn::Type>,
45    consts: HashMap<syn::Ident, syn::Expr>,
46    lifetimes: HashMap<syn::Lifetime, syn::Lifetime>,
47    self_type: Option<syn::Type>,
48    trait_path: Option<syn::Path>,
49}
50
51impl Substitution {
52    fn new(generics: &syn::Generics, trait_path: &syn::Path) -> syn::Result<Self> {
53        let supplied: Vec<_> = match &trait_path.segments.last().unwrap().arguments {
54            syn::PathArguments::AngleBracketed(args) => args.args.iter().collect(),
55            _ => Vec::new(),
56        };
57        let mut supplied = supplied.into_iter().peekable();
58        let mut result = Self::default();
59        for param in &generics.params {
60            match param {
61                syn::GenericParam::Type(param) => {
62                    let ty = match supplied.next() {
63                        Some(syn::GenericArgument::Type(ty)) => ty.clone(),
64                        None if param.default.is_some() => {
65                            let mut ty = param.default.clone().unwrap();
66                            // Only declaration defaults refer to earlier parameters;
67                            // supplied arguments already belong to the impl's scope.
68                            result.visit_type_mut(&mut ty);
69                            ty
70                        }
71                        _ => {
72                            return Err(syn::Error::new_spanned(
73                                trait_path,
74                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("expected a concrete argument for trait type parameter `{0}`",
                param.ident))
    })format!(
75                                    "expected a concrete argument for trait type parameter `{}`",
76                                    param.ident,
77                                ),
78                            ));
79                        }
80                    };
81                    result.types.insert(param.ident.clone(), ty);
82                }
83                syn::GenericParam::Const(param) => {
84                    let value = match supplied.next() {
85                        Some(syn::GenericArgument::Const(value)) => value.clone(),
86                        // syn parses a bare const name as a Type until its
87                        // declaration tells us which kind of parameter it is.
88                        Some(syn::GenericArgument::Type(ty)) => syn::parse2({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    _s
}quote::quote!(#ty))?,
89                        None if param.default.is_some() => {
90                            let mut value = param.default.clone().unwrap();
91                            result.visit_expr_mut(&mut value);
92                            value
93                        }
94                        _ => {
95                            return Err(syn::Error::new_spanned(
96                                trait_path,
97                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("expected a concrete argument for trait const parameter `{0}`",
                param.ident))
    })format!(
98                                    "expected a concrete argument for trait const parameter `{}`",
99                                    param.ident,
100                                ),
101                            ));
102                        }
103                    };
104                    result.consts.insert(param.ident.clone(), value);
105                }
106                syn::GenericParam::Lifetime(param) => {
107                    let lifetime = match supplied.peek() {
108                        Some(syn::GenericArgument::Lifetime(_)) => {
109                            let Some(syn::GenericArgument::Lifetime(value)) = supplied.next()
110                            else {
111                                ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
112                            };
113                            value.clone()
114                        }
115                        _ => ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_lifetime(&mut _s, "\'_");
        _s
    })syn::parse_quote!('_),
116                    };
117                    result.lifetimes.insert(param.lifetime.clone(), lifetime);
118                }
119            }
120        }
121        Ok(result)
122    }
123}
124
125impl VisitMut for Substitution {
126    fn visit_type_mut(&mut self, ty: &mut syn::Type) {
127        if let syn::Type::Path(path) = ty
128            && path.qself.is_none()
129            && path.path.segments.len() > 1
130            && path.path.segments[0].ident == "Self"
131            && self.self_type.is_some()
132            && self.trait_path.is_some()
133        {
134            let mut associated = path.path.clone();
135            associated.segments = associated.segments.into_iter().skip(1).collect();
136            self.visit_path_mut(&mut associated);
137            let concrete = self.self_type.as_ref().unwrap();
138            let trait_path = self.trait_path.as_ref().unwrap();
139            *ty = ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_lt(&mut _s);
        ::quote::ToTokens::to_tokens(&concrete, &mut _s);
        ::quote::__private::push_ident(&mut _s, "as");
        ::quote::ToTokens::to_tokens(&trait_path, &mut _s);
        ::quote::__private::push_gt(&mut _s);
        ::quote::__private::push_colon2(&mut _s);
        ::quote::ToTokens::to_tokens(&associated, &mut _s);
        _s
    })syn::parse_quote!(<#concrete as #trait_path>::#associated);
140            return;
141        }
142        if let syn::Type::Path(path) = ty
143            && path.qself.is_none()
144            && let Some(name) = path.path.get_ident()
145            && let Some(concrete) = self.types.get(name)
146        {
147            *ty = concrete.clone();
148            return;
149        }
150        syn::visit_mut::visit_type_mut(self, ty);
151    }
152
153    fn visit_expr_mut(&mut self, expr: &mut syn::Expr) {
154        if let syn::Expr::Path(path) = expr
155            && path.qself.is_none()
156            && let Some(name) = path.path.get_ident()
157            && let Some(value) = self.consts.get(name)
158        {
159            *expr = value.clone();
160            return;
161        }
162        syn::visit_mut::visit_expr_mut(self, expr);
163    }
164
165    fn visit_generic_argument_mut(&mut self, arg: &mut syn::GenericArgument) {
166        // `Wrapper<N>` parses N as a type, but a const parameter's declaration
167        // tells us it must become a const argument after substitution.
168        if let syn::GenericArgument::Type(syn::Type::Path(path)) = arg
169            && let Some(name) = path.path.get_ident()
170            && let Some(value) = self.consts.get(name)
171        {
172            *arg = ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Brace,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                ::quote::ToTokens::to_tokens(&value, &mut _s);
                _s
            });
        _s
    })syn::parse_quote!({ #value });
173            return;
174        }
175        syn::visit_mut::visit_generic_argument_mut(self, arg);
176    }
177
178    fn visit_lifetime_mut(&mut self, lifetime: &mut syn::Lifetime) {
179        if let Some(concrete) = self.lifetimes.get(lifetime) {
180            *lifetime = concrete.clone();
181        }
182    }
183}
184
185#[cfg(test)]
186mod tests {
187    use super::*;
188    use quote::quote;
189
190    #[test]
191    fn nested_types_consts_lifetimes_and_parameter_defaults() {
192        let generics = syn::parse_quote!(<'a, T, const N: usize, U = Vec<T>>);
193        let path = syn::parse_quote!(Example<'static, i32, 3>);
194        let mut sub = Substitution::new(&generics, &path).unwrap();
195        let mut ty: syn::Type = syn::parse_quote!((&'a [T; N], U, SizedBuffer<N>));
196        sub.visit_type_mut(&mut ty);
197        assert_eq!(
198            quote!(#ty).to_string(),
199            quote!((&'static [i32; 3], Vec<i32>, SizedBuffer<{ 3 }>)).to_string()
200        );
201    }
202
203    #[test]
204    fn caller_types_are_not_reinterpreted_as_declaration_parameters() {
205        let generics = syn::parse_quote!(<T, U>);
206        let path = syn::parse_quote!(Example<i32, T>);
207        let mut sub = Substitution::new(&generics, &path).unwrap();
208        let mut ty: syn::Type = syn::parse_quote!((T, U));
209        sub.visit_type_mut(&mut ty);
210        assert_eq!(quote!(#ty).to_string(), quote!((i32, T)).to_string());
211    }
212
213    #[test]
214    fn only_omitted_defaults_get_synthetic_signatures() {
215        let implementation = syn::parse_quote!(impl Example<i32> for Host {
216            fn own(&self) -> i32 { 9 }
217        });
218        let declaration = vec![
219            syn::parse_quote!(
220                fn own(&self) -> T {}
221            ),
222            syn::parse_quote!(
223                fn required(&self) -> T;
224            ),
225            syn::parse_quote!(
226                #[miniextendr(r_name = "values")]
227                fn inherited(&self, x: Vec<T>) -> T {}
228            ),
229        ];
230        let methods = inherited_methods(
231            &implementation,
232            &declaration,
233            &syn::parse_quote!(<T>),
234            &syn::parse_quote!(Example<i32>),
235        )
236        .unwrap();
237        assert_eq!(methods.len(), 1);
238        let method = &methods[0];
239        assert_eq!(
240            quote!(#method).to_string(),
241            quote!(
242                #[miniextendr(r_name = "values")]
243                fn inherited(&self, x: Vec<i32>) -> i32 {}
244            )
245            .to_string()
246        );
247    }
248}