Skip to main content

min_specialization/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod normalize;
4mod substitute;
5
6use normalize::WherePredicateBinding;
7use proc_macro::TokenStream as TokenStream1;
8use proc_macro2::{Span, TokenStream};
9use proc_macro_error::{abort, proc_macro_error};
10use std::collections::{HashMap, HashSet};
11use substitute::{Substitute, SubstituteEnvironment};
12use syn::punctuated::Punctuated;
13use syn::spanned::Spanned;
14use syn::visit_mut::VisitMut;
15use syn::*;
16use template_quote::quote;
17
18fn replace_type_of_trait_item_fn(mut ty: TraitItemFn, from: &Type, to: &Type) -> TraitItemFn {
19    use syn::visit_mut::VisitMut;
20    struct Visitor<'a>(&'a Type, &'a Type);
21    impl<'a> VisitMut for Visitor<'a> {
22        fn visit_type_mut(&mut self, ty: &mut Type) {
23            if &ty == &self.0 {
24                *ty = self.1.clone();
25            }
26            syn::visit_mut::visit_type_mut(self, ty)
27        }
28    }
29    let mut visitor = Visitor(from, to);
30    visitor.visit_trait_item_fn_mut(&mut ty);
31    ty
32}
33
34/// Replace every named lifetime (other than `'static`) in a type with `to`.
35/// Used to refer to a specialization's self type from inside the (lifetime-agnostic)
36/// dispatcher: `'static` for the type-id comparison (which erases lifetimes anyway),
37/// and `'_` for the actual call (so the lifetime is inferred and the transmute stays
38/// an identity conversion at the caller's lifetime).
39fn map_lifetimes(mut ty: Type, to: Lifetime) -> Type {
40    struct V(Lifetime);
41    impl VisitMut for V {
42        fn visit_lifetime_mut(&mut self, i: &mut Lifetime) {
43            if i.ident != "static" {
44                *i = self.0.clone();
45            }
46        }
47    }
48    V(to).visit_type_mut(&mut ty);
49    ty
50}
51
52fn check_defaultness(item_impl: &ItemImpl) -> Option<bool> {
53    let mut ret = false;
54    // does not support impl-level default keyword
55    if item_impl.defaultness.is_some() {
56        return None;
57    }
58    for item in item_impl.items.iter() {
59        match item {
60            ImplItem::Const(item_const) if item_const.defaultness.is_some() => {
61                return None;
62            }
63            ImplItem::Fn(item_method) if item_method.defaultness.is_some() => {
64                ret = true;
65            }
66            ImplItem::Type(item_type) if item_type.defaultness.is_some() => {
67                return None;
68            }
69            _ => (),
70        }
71    }
72    Some(ret)
73}
74
75fn normalize_params_and_predicates(
76    impl_: &ItemImpl,
77) -> (HashSet<GenericParam>, HashSet<WherePredicateBinding>) {
78    let (mut gps, mut wps) = (HashSet::new(), HashSet::new());
79    for gp in impl_.generics.params.iter() {
80        let (gp, nwps) = normalize::normalize_generic_param(gp.clone());
81        gps.insert(gp);
82        wps.extend(nwps);
83    }
84    if let Some(wc) = &impl_.generics.where_clause {
85        for p in wc.predicates.iter() {
86            let nwps = normalize::normalize_where_predicate(p.clone());
87            wps.extend(nwps);
88        }
89    }
90    (gps, wps)
91}
92
93fn get_param_ident(p: GenericParam) -> Option<Ident> {
94    match p {
95        GenericParam::Type(tp) => Some(tp.ident),
96        _ => None,
97    }
98}
99
100fn get_type_ident(ty: Type) -> Option<Ident> {
101    match ty {
102        Type::Path(tp) if tp.qself.is_none() => tp.path.get_ident().cloned(),
103        _ => None,
104    }
105}
106
107fn find_type_ident(ty: &Type, ident: &Ident) -> bool {
108    use syn::visit::Visit;
109    struct Visitor<'a>(&'a Ident, bool);
110    impl<'ast, 'a> Visit<'ast> for Visitor<'a> {
111        fn visit_type(&mut self, i: &'ast Type) {
112            match i {
113                Type::Path(tp) if tp.qself.is_none() && tp.path.get_ident() == Some(&self.0) => {
114                    self.1 = true;
115                }
116                _ => {
117                    syn::visit::visit_type(self, i);
118                }
119            }
120        }
121    }
122    let mut vis = Visitor(ident, false);
123    vis.visit_type(ty);
124    vis.1
125}
126
127fn get_trivial_substitutions(
128    special_params: &HashSet<Ident>,
129    substitution: &HashMap<Ident, Type>,
130) -> Vec<(Ident, Ident)> {
131    substitution
132        .iter()
133        .filter_map(|(d, s)| {
134            get_type_ident(s.clone())
135                .and_then(|i| special_params.iter().find(|ii| &&i == ii).cloned())
136                .map(|s| (d.clone(), s))
137        })
138        .collect()
139}
140
141fn substitute_impl(
142    default_impl: &ItemImpl,
143    special_impl: &ItemImpl,
144) -> Vec<(HashMap<Ident, Type>, usize)> {
145    let (d_ps, d_ws) = normalize_params_and_predicates(default_impl);
146    let (s_ps, s_ws) = normalize_params_and_predicates(special_impl);
147    // Remove `Self` type
148    let self_ident = Ident::new("Self", Span::call_site());
149    let d_ws = d_ws
150        .into_iter()
151        .map(|w| {
152            w.replace_type_params(
153                core::iter::once((self_ident.clone(), default_impl.self_ty.as_ref().clone()))
154                    .collect(),
155            )
156        })
157        .collect::<HashSet<_>>();
158    let s_ws = s_ws
159        .into_iter()
160        .map(|w| {
161            w.replace_type_params(
162                core::iter::once((self_ident.clone(), special_impl.self_ty.as_ref().clone()))
163                    .collect(),
164            )
165        })
166        .collect::<HashSet<_>>();
167    let s_ps: HashSet<_> = s_ps.into_iter().filter_map(get_param_ident).collect();
168    let env = SubstituteEnvironment {
169        general_params: d_ps.into_iter().filter_map(get_param_ident).collect(),
170    };
171    let s = env.substitute(&d_ws, &s_ws)
172        * env.substitute(
173            &default_impl.trait_.as_ref().unwrap().1,
174            &special_impl.trait_.as_ref().unwrap().1,
175        )
176        * env.substitute(&*default_impl.self_ty, &*special_impl.self_ty);
177    // Filter substitutions, which has parameters in replacement
178    s.0.into_iter()
179        .filter(|m| {
180            m.iter().all(|(_, ty)| {
181                s_ps.iter().all(|i| {
182                    &get_type_ident(ty.clone()).as_ref() == &Some(i) || !find_type_ident(ty, &i)
183                })
184            })
185        })
186        .map(|r| {
187            (
188                r.clone(),
189                r.len() - get_trivial_substitutions(&s_ps, &r).len(),
190            )
191        })
192        .collect()
193}
194
195trait ReplaceTypeParams {
196    fn replace_type_params(self, map: HashMap<Ident, Type>) -> Self;
197}
198
199const _: () = {
200    fn filter_map_with_generics(
201        map: &HashMap<Ident, Type>,
202        generics: &Generics,
203    ) -> HashMap<Ident, Type> {
204        map.clone()
205            .into_iter()
206            .filter(|(k, _)| {
207                generics
208                    .params
209                    .iter()
210                    .filter_map(|o| {
211                        if let GenericParam::Type(pt) = o {
212                            Some(&pt.ident)
213                        } else {
214                            None
215                        }
216                    })
217                    .all(|id| k != id)
218            })
219            .collect()
220    }
221    #[derive(Clone)]
222    struct Visitor(HashMap<Ident, Type>);
223    impl VisitMut for Visitor {
224        fn visit_type_mut(&mut self, i: &mut Type) {
225            if let Type::Path(tp) = i {
226                if let Some(id) = tp.path.get_ident() {
227                    if let Some(replaced) = self.0.get(id) {
228                        *i = replaced.clone();
229                        return;
230                    }
231                }
232            }
233            syn::visit_mut::visit_type_mut(self, i)
234        }
235        fn visit_item_fn_mut(&mut self, i: &mut ItemFn) {
236            let mut this = Visitor(filter_map_with_generics(&self.0, &i.sig.generics));
237            syn::visit_mut::visit_item_fn_mut(&mut this, i);
238        }
239        fn visit_item_impl_mut(&mut self, i: &mut ItemImpl) {
240            let mut this = Visitor(filter_map_with_generics(&self.0, &i.generics));
241            syn::visit_mut::visit_item_impl_mut(&mut this, i);
242        }
243        fn visit_item_trait_mut(&mut self, i: &mut ItemTrait) {
244            let mut this = Visitor(filter_map_with_generics(&self.0, &i.generics));
245            syn::visit_mut::visit_item_trait_mut(&mut this, i);
246        }
247        fn visit_item_struct_mut(&mut self, i: &mut ItemStruct) {
248            let mut this = Visitor(filter_map_with_generics(&self.0, &i.generics));
249            syn::visit_mut::visit_item_struct_mut(&mut this, i);
250        }
251        fn visit_item_enum_mut(&mut self, i: &mut ItemEnum) {
252            let mut this = Visitor(filter_map_with_generics(&self.0, &i.generics));
253            syn::visit_mut::visit_item_enum_mut(&mut this, i);
254        }
255        fn visit_item_type_mut(&mut self, i: &mut ItemType) {
256            let mut this = Visitor(filter_map_with_generics(&self.0, &i.generics));
257            syn::visit_mut::visit_item_type_mut(&mut this, i);
258        }
259        fn visit_item_union_mut(&mut self, i: &mut ItemUnion) {
260            let mut this = Visitor(filter_map_with_generics(&self.0, &i.generics));
261            syn::visit_mut::visit_item_union_mut(&mut this, i);
262        }
263    }
264
265    impl ReplaceTypeParams for WherePredicateBinding {
266        fn replace_type_params(self, map: HashMap<Ident, Type>) -> Self {
267            match self {
268                WherePredicateBinding::Lifetime(lt) => {
269                    WherePredicateBinding::Lifetime(lt.replace_type_params(map))
270                }
271                WherePredicateBinding::Type(pt) => {
272                    WherePredicateBinding::Type(pt.replace_type_params(map))
273                }
274                WherePredicateBinding::Eq {
275                    lhs_ty,
276                    eq_token,
277                    rhs_ty,
278                } => WherePredicateBinding::Eq {
279                    lhs_ty: lhs_ty.replace_type_params(map.clone()),
280                    eq_token,
281                    rhs_ty: rhs_ty.replace_type_params(map),
282                },
283            }
284        }
285    }
286    impl ReplaceTypeParams for PredicateType {
287        fn replace_type_params(mut self, map: HashMap<Ident, Type>) -> Self {
288            let mut visitor = Visitor(map);
289            visitor.visit_predicate_type_mut(&mut self);
290            self
291        }
292    }
293    impl ReplaceTypeParams for PredicateLifetime {
294        fn replace_type_params(mut self, map: HashMap<Ident, Type>) -> Self {
295            let mut visitor = Visitor(map);
296            visitor.visit_predicate_lifetime_mut(&mut self);
297            self
298        }
299    }
300    impl ReplaceTypeParams for ImplItemFn {
301        fn replace_type_params(mut self, map: HashMap<Ident, Type>) -> Self {
302            let mut visitor = Visitor(map);
303            visitor.visit_impl_item_fn_mut(&mut self);
304            self
305        }
306    }
307    impl ReplaceTypeParams for Type {
308        fn replace_type_params(mut self, map: HashMap<Ident, Type>) -> Self {
309            let mut visitor = Visitor(map);
310            visitor.visit_type_mut(&mut self);
311            self
312        }
313    }
314};
315
316fn contains_generics_param(param: &GenericParam, ty: &Type) -> bool {
317    use syn::visit::Visit;
318    struct Visitor<'a>(&'a GenericParam, bool);
319    impl<'ast, 'a> Visit<'ast> for Visitor<'a> {
320        fn visit_lifetime(&mut self, i: &Lifetime) {
321            if matches!(&self.0, GenericParam::Lifetime(l) if &l.lifetime == i) {
322                self.1 = true;
323            }
324        }
325        fn visit_type_path(&mut self, i: &TypePath) {
326            if matches!(
327                (&self.0, &i.qself, i.path.get_ident()),
328                (GenericParam::Type(TypeParam {ident, ..}), &None, Some(id)) |
329                (GenericParam::Const(ConstParam {ident, ..}), &None, Some(id))
330                if ident == id
331            ) {
332                self.1 = true;
333            } else {
334                syn::visit::visit_type_path(self, i)
335            }
336        }
337    }
338    let mut visitor = Visitor(param, false);
339    visitor.visit_type(ty);
340    visitor.1
341}
342
343/// A name key for de-duplicating generic parameters by what they introduce.
344fn generic_param_key(p: &GenericParam) -> String {
345    match p {
346        GenericParam::Lifetime(l) => format!("'{}", l.lifetime.ident),
347        GenericParam::Type(t) => t.ident.to_string(),
348        GenericParam::Const(c) => c.ident.to_string(),
349    }
350}
351
352/// Whether a generic parameter is referenced anywhere in a function signature's
353/// argument or return types (used to decide which params the inner impl must declare).
354fn param_in_sig(p: &GenericParam, sig: &Signature) -> bool {
355    let used = |ty: &Type| contains_generics_param(p, ty);
356    sig.inputs.iter().any(|arg| match arg {
357        FnArg::Typed(pt) => used(&pt.ty),
358        FnArg::Receiver(r) => used(&r.ty),
359    }) || matches!(&sig.output, ReturnType::Type(_, ty) if used(ty))
360}
361
362fn specialize_item_fn_trait(
363    impl_: &ItemImpl,
364    extra_generics: &Punctuated<GenericParam, Token![,]>,
365    ident: &Ident,
366    fn_ident: &Ident,
367    impl_item_fn: &ImplItemFn,
368    needs_sized_bound: bool,
369    self_ty: &Type,
370) -> (TokenStream, Punctuated<GenericParam, Token![,]>) {
371    let trait_path = &impl_.trait_.as_ref().unwrap().1;
372    let trait_ty = Type::Path(TypePath {
373        qself: None,
374        path: trait_path.clone(),
375    });
376
377    let mut item_fn = replace_type_of_trait_item_fn(
378        TraitItemFn {
379            attrs: vec![],
380            sig: impl_item_fn.sig.clone(),
381            default: None,
382            semi_token: Some(Default::default()),
383        },
384        &impl_.self_ty,
385        &parse_quote!(Self),
386    );
387    item_fn.sig.ident = fn_ident.clone();
388    // The inner trait method is a *declaration* (no body), so its argument patterns
389    // must be plain identifiers; the implementing method below keeps the original
390    // patterns and body. Trait/impl signatures only need matching types, not names.
391    set_argument_named(&mut item_fn.sig);
392
393    // Candidate generics: this impl's own parameters plus the specialization's
394    // parameters (e.g. lifetimes appearing in a specialized type like `Foo<'a>` or
395    // `&'a str`), de-duplicated by name. We then keep only those actually referenced.
396    let mut pool: Vec<GenericParam> = Vec::new();
397    for p in impl_.generics.params.iter().chain(extra_generics.iter()) {
398        let key = generic_param_key(p);
399        if !pool.iter().any(|q| generic_param_key(q) == key) {
400            pool.push(p.clone());
401        }
402    }
403
404    // Parameters referenced by the self type or trait path are declared on the inner
405    // impl (e.g. `impl<'a> .. for Foo<'a>`).
406    let impl_generics: Punctuated<_, Token![,]> = pool
407        .iter()
408        .filter(|p| contains_generics_param(p, &trait_ty) || contains_generics_param(p, self_ty))
409        .cloned()
410        .collect();
411    // A specialization lifetime that appears only in the *method signature* (not the
412    // self type or trait path) is declared as a method-level lifetime instead, e.g.
413    // `impl Tr<&'a str>`'s method becomes `fn inner<'a>(&self, u: &'a str)`.
414    let mut method_extra_lifetimes: Vec<GenericParam> = pool
415        .iter()
416        .filter(|p| matches!(p, GenericParam::Lifetime(_)))
417        .filter(|p| {
418            param_in_sig(p, &item_fn.sig)
419                && !impl_generics
420                    .iter()
421                    .any(|q| generic_param_key(q) == generic_param_key(p))
422        })
423        .cloned()
424        .collect();
425    for p in &mut method_extra_lifetimes {
426        if let GenericParam::Lifetime(l) = p {
427            l.attrs.clear();
428            l.colon_token = None;
429            l.bounds = Punctuated::new();
430        }
431    }
432    let ty_generics: Punctuated<_, Token![,]> = pool
433        .iter()
434        .filter(|p| contains_generics_param(p, &trait_ty))
435        .map(|p| {
436            let mut p = p.clone();
437            match &mut p {
438                GenericParam::Lifetime(p) => {
439                    p.attrs = Vec::new();
440                    p.colon_token = None;
441                    p.bounds = Punctuated::new();
442                }
443                GenericParam::Type(t) => {
444                    t.attrs = Vec::new();
445                    t.colon_token = None;
446                    t.bounds = Punctuated::new();
447                    t.eq_token = None;
448                    t.default = None;
449                }
450                GenericParam::Const(c) => {
451                    c.attrs = Vec::new();
452                    c.eq_token = None;
453                    c.default = None;
454                }
455            }
456            p
457        })
458        .collect();
459    let mut impl_item_fn = impl_item_fn.clone();
460    impl_item_fn.defaultness = None;
461    impl_item_fn.sig.ident = fn_ident.clone();
462    // Declare the method-level lifetimes on both the trait declaration and the impl
463    // method (their signatures must match), in front of any existing generics.
464    for lt in method_extra_lifetimes.into_iter().rev() {
465        item_fn.sig.generics.params.insert(0, lt.clone());
466        impl_item_fn.sig.generics.params.insert(0, lt);
467    }
468    let out = quote! {
469        trait #ident<#ty_generics>: #trait_path
470            #(if needs_sized_bound) { + ::core::marker::Sized }
471        {
472            #item_fn
473        }
474        impl<#impl_generics> #ident<#ty_generics> for #self_ty
475        #{&impl_.generics.where_clause}
476        {
477            #impl_item_fn
478        }
479    };
480    (out, ty_generics)
481}
482
483/// Replace every by-value argument pattern with a fresh, plain identifier.
484///
485/// This is applied to the signatures that are *re-emitted* by the macro: the
486/// outer dispatcher's signature (whose body only forwards its arguments) and the
487/// generated inner-trait method *declarations* (which are bodyless, where any
488/// non-trivial pattern is rejected by `E0642`). It must NOT be applied to the
489/// method bodies, which keep their original patterns. Forwarding a fresh
490/// identifier is always a valid expression, which avoids the historical panics on
491/// `mut x` / `ref x` and the `E0642` on tuple/struct patterns.
492fn set_argument_named(sig: &mut Signature) {
493    for (n, arg) in sig.inputs.iter_mut().enumerate() {
494        if let FnArg::Typed(PatType { pat, .. }) = arg {
495            *pat = Box::new(Pat::Ident(PatIdent {
496                attrs: Vec::new(),
497                by_ref: None,
498                mutability: None,
499                ident: Ident::new(&format!("_min_specialization_v{}", n), pat.span()),
500                subpat: None,
501            }));
502        }
503    }
504}
505
506fn specialize_item_fn(
507    default_impl: &ItemImpl,
508    mut ifn: ImplItemFn,
509    specials: Vec<(HashMap<Ident, Type>, ItemImpl, ImplItemFn)>,
510    needs_sized_bound: bool,
511) -> ImplItemFn {
512    let itrait_name = Ident::new("__MinSpecialization_InnerTrait", Span::call_site());
513    let ifn_name = Ident::new("__min_specialization__inner_fn", Span::call_site());
514    // Keep the original method (patterns + body) for the inner default-trait impl;
515    // the outer dispatcher uses freshly-named arguments so it can forward them.
516    let orig_ifn = ifn.clone();
517    set_argument_named(&mut ifn.sig);
518    // A method may have its own generic parameters. Inside the dispatcher those are
519    // in scope (the outer method declares them), so we forward them to the inner
520    // method as an explicit turbofish. This pins the inner method's generics across
521    // the type-erasing transmute (otherwise they could not be inferred -> `E0282`).
522    // Forwarding is positional, so the inner method's parameter names are irrelevant.
523    let method_turbofish: TokenStream = {
524        let args: Vec<&Ident> = ifn
525            .sig
526            .generics
527            .params
528            .iter()
529            .filter_map(|p| match p {
530                GenericParam::Type(t) => Some(&t.ident),
531                GenericParam::Const(c) => Some(&c.ident),
532                GenericParam::Lifetime(_) => None,
533            })
534            .collect();
535        if args.is_empty() {
536            quote! {}
537        } else {
538            quote! { ::<#(#args),*> }
539        }
540    };
541    let specials_out = specials
542        .into_iter()
543        .enumerate()
544        .map(|(n, (m, simpl, mut sfn))| {
545            let strait_name = Ident::new(
546                &format!("__MinSpecialization_InnerTrait_{}", n),
547                Span::call_site(),
548            );
549            let sfn_name = Ident::new(
550                &format!("__min_specialization__inner_fn_{}", n),
551                Span::call_site(),
552            );
553            sfn.sig.ident = sfn_name.clone();
554            let mut condition = quote! {true};
555            let mut replacement = HashMap::new();
556            for (lhs, rhs) in m.iter() {
557                if let Some(rhs) = get_type_ident(rhs.clone()) {
558                    if simpl
559                        .generics
560                        .params
561                        .iter()
562                        .filter_map(|p| {
563                            if let GenericParam::Type(p) = p {
564                                Some(&p.ident)
565                            } else {
566                                None
567                            }
568                        })
569                        .any(|p| p == &rhs)
570                    {
571                        let lhs = Type::Path(TypePath {
572                            qself: None,
573                            path: Path {
574                                leading_colon: None,
575                                segments: Some(PathSegment {
576                                    ident: lhs.clone(),
577                                    arguments: PathArguments::None,
578                                })
579                                .into_iter()
580                                .collect(),
581                            },
582                        });
583                        replacement.insert(rhs, lhs);
584                        continue;
585                    }
586                }
587                // The type-id check is lifetime-agnostic, so erase the special's
588                // lifetimes to `'static` (which is always nameable) to avoid
589                // referencing the special impl's lifetimes, which are not in scope
590                // in this dispatcher.
591                let rhs = map_lifetimes(rhs.clone(), parse_quote!('static));
592                condition.extend(quote! {
593                    && __min_specialization_type_id::<#lhs>()
594                        == __min_specialization_type_id::<#rhs>()
595                });
596            }
597            let sfn = sfn.replace_type_params(replacement.clone());
598            let replaced_self_ty = default_impl.self_ty.clone().replace_type_params(m.clone());
599            // For the actual call, refer to the self type with inferred (`'_`)
600            // lifetimes so they unify with the caller's; the inner impl below is
601            // generic over those lifetimes, keeping the transmute an identity.
602            let replaced_self_ty_call = map_lifetimes(replaced_self_ty.clone(), parse_quote!('_));
603            let (special_trait_impl, special_trait_params) = specialize_item_fn_trait(
604                default_impl,
605                &simpl.generics.params,
606                &strait_name,
607                &sfn_name,
608                &sfn,
609                needs_sized_bound,
610                &replaced_self_ty,
611            );
612            quote! {
613                if #condition {
614                    #special_trait_impl
615                    __min_specialization_transmute(
616                        <#replaced_self_ty_call as #strait_name<
617                            #(for par in &special_trait_params), {
618                                #(if let GenericParam::Type(TypeParam{ident, ..}) = par) {
619                                    #(if let Some(ident) = replacement.get(ident)) {
620                                        #ident
621                                    }
622                                    #(else) {
623                                        #ident
624                                    }
625                                } #(else) {
626                                    #par
627                                }
628                            }
629                        >>::#sfn_name #{&method_turbofish}(
630                            #(for arg in &ifn.sig.inputs), {
631                                #(if let FnArg::Receiver(_) = arg) {
632                                    __min_specialization_transmute(self)
633                                }
634                                #(if let FnArg::Typed(pt) = arg) {
635                                    __min_specialization_transmute(#{&pt.pat})
636                                }
637                            }
638                        )
639                    )
640                } else
641            }
642        })
643        .collect::<Vec<_>>();
644    let no_extra_generics = Punctuated::new();
645    let (default_trait_impl, default_trait_params) = specialize_item_fn_trait(
646        default_impl,
647        &no_extra_generics,
648        &itrait_name,
649        &ifn_name,
650        &orig_ifn,
651        needs_sized_bound,
652        &default_impl.self_ty,
653    );
654    let inner = quote! {
655        #(for attr in &ifn.attrs) {#attr}
656        #{&ifn.vis}
657        #{&ifn.sig}
658        {
659            // Sound, lifetime-erased type identity. `TypeId::of` requires `'static`,
660            // which would forbid specializing on borrowed types such as `&str`. We
661            // instead obtain the `TypeId` of the *lifetime-erased* type via a trait
662            // object whose existential lifetime is widened to `'static` (the value is
663            // a ZST `PhantomData`, so no non-`'static` data is ever accessed). The
664            // result identifies a type up to its lifetimes, which is exactly the
665            // granularity specialization needs — `min_specialization` never dispatches
666            // on lifetimes. `TypeId` is collision-free, so this has neither the false
667            // positives (identical-code-folding) nor the false negatives of comparing
668            // function-pointer addresses.
669            fn __min_specialization_type_id<T: ?::core::marker::Sized>() -> ::core::any::TypeId {
670                trait __MinSpecializationNonStaticAny {
671                    fn __min_specialization_type_id(&self) -> ::core::any::TypeId
672                    where
673                        Self: 'static;
674                }
675                impl<T: ?::core::marker::Sized> __MinSpecializationNonStaticAny
676                    for ::core::marker::PhantomData<T>
677                {
678                    fn __min_specialization_type_id(&self) -> ::core::any::TypeId
679                    where
680                        Self: 'static,
681                    {
682                        ::core::any::TypeId::of::<T>()
683                    }
684                }
685                let it = ::core::marker::PhantomData::<T>;
686                let it: &dyn __MinSpecializationNonStaticAny = &it;
687                let it: &(dyn __MinSpecializationNonStaticAny + 'static) =
688                    unsafe { ::core::mem::transmute(it) };
689                it.__min_specialization_type_id()
690            }
691            // Whenever a branch is taken, the generic `T` and the concrete branch type
692            // are the same type (up to lifetimes), so the transmutes below are identity
693            // conversions. The size/align assertions are retained purely as cheap
694            // defense-in-depth; they always hold.
695            fn __min_specialization_transmute<T, U>(input: T) -> U {
696                ::core::assert_eq!(
697                    ::core::mem::size_of::<T>(),
698                    ::core::mem::size_of::<U>()
699                );
700                ::core::assert_eq!(
701                    ::core::mem::align_of::<T>(),
702                    ::core::mem::align_of::<U>()
703                );
704                let mut rhs = ::core::mem::MaybeUninit::new(input);
705                let mut lhs = ::core::mem::MaybeUninit::<U>::uninit();
706                unsafe {
707                    let rhs = ::core::mem::transmute::<
708                        _, &mut ::core::mem::MaybeUninit<U>
709                    >(&mut rhs);
710                    ::core::ptr::swap(lhs.as_mut_ptr(), rhs.as_mut_ptr());
711                    lhs.assume_init()
712                }
713            }
714            #( #specials_out)*
715            {
716                #default_trait_impl
717                <#{&default_impl.self_ty} as #itrait_name<#default_trait_params>>::#ifn_name #{&method_turbofish}(
718                    #(for arg in &ifn.sig.inputs),{
719                        #(if let FnArg::Receiver(Receiver{self_token, ..}) = arg) {
720                            #self_token
721                        }
722                        #(if let FnArg::Typed(PatType{pat, ..}) = arg) {
723                            #pat
724                        }
725                    }
726                )
727            }
728        }
729    };
730    parse2(inner).unwrap_or_else(|e| {
731        abort!(
732            e.span(),
733            "#[specialization] generated code that failed to parse: {}", e;
734            note = "this is a bug in min-specialization; please report it with the offending impl"
735        )
736    })
737}
738
739fn check_needs_sized_bound(impl_: &ItemImpl) -> bool {
740    impl_
741        .items
742        .iter()
743        .filter_map(|item| {
744            if let ImplItem::Fn(item) = item {
745                Some(item)
746            } else {
747                None
748            }
749        })
750        .any(|item| {
751            item.sig
752                .inputs
753                .iter()
754                .filter_map(|item| {
755                    if let FnArg::Typed(PatType { ty, .. }) = item {
756                        Some(&*ty)
757                    } else {
758                        None
759                    }
760                })
761                .chain(if let ReturnType::Type(_, ty) = &item.sig.output {
762                    Some(&*ty)
763                } else {
764                    None
765                })
766                .any(|ty| ty == &impl_.self_ty || ty == &parse_quote!(Self))
767        })
768}
769
770/// Remove every `default` keyword from an impl and its items, turning it into an
771/// ordinary impl. Leaving a stray `default fn` behind triggers `E0658`
772/// ("specialization is unstable") on stable.
773fn strip_defaultness(impl_: &mut ItemImpl) {
774    impl_.defaultness = None;
775    for item in impl_.items.iter_mut() {
776        match item {
777            ImplItem::Fn(f) => f.defaultness = None,
778            ImplItem::Const(c) => c.defaultness = None,
779            ImplItem::Type(t) => t.defaultness = None,
780            _ => {}
781        }
782    }
783}
784
785fn specialize_impl(
786    mut default_impl: ItemImpl,
787    special_impls: Vec<(ItemImpl, HashMap<Ident, Type>)>,
788) -> ItemImpl {
789    if special_impls.len() == 0 {
790        // A default impl with no matching specialization is just an ordinary impl;
791        // strip the `default` keyword so it does not leak `E0658` on stable.
792        strip_defaultness(&mut default_impl);
793        return default_impl;
794    }
795    let needs_sized_bound = check_needs_sized_bound(&default_impl);
796    let default_fn_idents: HashSet<Ident> = default_impl
797        .items
798        .iter()
799        .filter_map(|item| match item {
800            ImplItem::Fn(ifn) => Some(ifn.sig.ident.clone()),
801            _ => None,
802        })
803        .collect();
804    let mut fn_map = HashMap::new();
805    for (simpl, ssub) in special_impls.into_iter() {
806        for item in simpl.items.iter() {
807            match item {
808                ImplItem::Fn(ifn) => {
809                    // A specialization may only override methods that the default impl
810                    // itself defines; otherwise the override would be silently dropped.
811                    if !default_fn_idents.contains(&ifn.sig.ident) {
812                        abort!(
813                            ifn.sig.ident.span(),
814                            "`{}` is overridden in a specialization but is not defined in the \
815                             default impl, so it cannot be specialized",
816                            ifn.sig.ident;
817                            help = "give the default impl a `default fn {}` to specialize",
818                            ifn.sig.ident
819                        );
820                    }
821                    fn_map
822                        .entry(ifn.sig.ident.clone())
823                        .or_insert(Vec::new())
824                        .push((ssub.clone(), simpl.clone(), ifn.clone()));
825                }
826                o => abort!(o.span(), "This item cannot be specialized"),
827            }
828        }
829    }
830    let mut out = Vec::new();
831    for item in &default_impl.items {
832        match item {
833            ImplItem::Fn(ifn) => {
834                let specials = fn_map.get(&ifn.sig.ident).cloned().unwrap_or(Vec::new());
835                out.push(ImplItem::Fn(specialize_item_fn(
836                    &default_impl,
837                    ifn.clone(),
838                    specials,
839                    needs_sized_bound,
840                )));
841            }
842            o => out.push(o.clone()),
843        }
844    }
845    default_impl.items = out;
846    default_impl
847}
848
849fn specialize_trait(
850    default_impls: Vec<ItemImpl>,
851    special_impls: Vec<ItemImpl>,
852) -> (Vec<ItemImpl>, Vec<ItemImpl>) {
853    let mut default_specials: Vec<Vec<(ItemImpl, HashMap<Ident, Type>)>> =
854        default_impls.iter().map(|_| Vec::new()).collect();
855    let mut orphan_impls = Vec::new();
856    for s in special_impls.into_iter() {
857        // Attach each specialization to the default impl it refines: the one needing
858        // the fewest non-trivial substitutions. `min_by_key` keeps the first such
859        // default on ties, so the choice follows source order and is deterministic.
860        let best = default_impls
861            .iter()
862            .enumerate()
863            .flat_map(|(i, d)| substitute_impl(d, &s).into_iter().map(move |(sub, n)| (i, sub, n)))
864            .min_by_key(|(_, _, n)| *n);
865        if let Some((i, sub, _)) = best {
866            default_specials[i].push((s, sub));
867        } else {
868            orphan_impls.push(s);
869        }
870    }
871    // Reject literally-overlapping specializations (same trait + same self type
872    // refining the same default impl). Real specialization rejects these as a
873    // coherence error (`E0119`); without this check they would silently fold into
874    // the dispatch chain with a nondeterministic winner.
875    for specials in &default_specials {
876        for (i, (a, _)) in specials.iter().enumerate() {
877            for (b, _) in specials.iter().skip(i + 1) {
878                if a.trait_.as_ref().map(|t| &t.1) == b.trait_.as_ref().map(|t| &t.1)
879                    && a.self_ty == b.self_ty
880                {
881                    abort!(
882                        b.span(),
883                        "conflicting specializations: this impl overlaps another \
884                         specialization of the same trait for the same type";
885                        note = "min-specialization cannot order overlapping specializations"
886                    );
887                }
888            }
889        }
890    }
891    let impls = default_impls
892        .into_iter()
893        .zip(default_specials)
894        .map(|(d, specials)| specialize_impl(d, specials))
895        .collect();
896    (impls, orphan_impls)
897}
898
899fn specialization_mod(module: ItemMod) -> TokenStream {
900    let (_, content) = if let Some(inner) = module.content {
901        inner
902    } else {
903        abort!(module.span(), "Require mod content")
904    };
905    // Source order is preserved (plain `Vec`s, not `HashSet`s) so that codegen —
906    // and in particular the order of the runtime dispatch chain — is deterministic
907    // across compilations.
908    let (mut defaults, mut specials): (Vec<ItemImpl>, Vec<ItemImpl>) = (Vec::new(), Vec::new());
909    let mut generated_content = Vec::new();
910    for item in content.into_iter() {
911        if let Item::Impl(item_impl) = &item {
912            if item_impl.trait_.is_some() {
913                if let Some(defaultness) = check_defaultness(&item_impl) {
914                    if defaultness {
915                        defaults.push(item_impl.clone());
916                    } else {
917                        specials.push(item_impl.clone());
918                    }
919                    continue;
920                }
921            }
922        }
923        generated_content.push(item);
924    }
925    let (impls, orphans) = specialize_trait(defaults, specials);
926    generated_content.extend(impls.into_iter().map(Item::Impl));
927    generated_content.extend(orphans.into_iter().map(Item::Impl));
928
929    quote! {
930        #(for attr in &module.attrs) { #attr }
931        #{&module.vis}
932        #{&module.mod_token}
933        #{&module.ident}
934        {
935            #(#generated_content)*
936        }
937    }
938}
939
940/// Emulate the unstable [`min_specialization`] feature on **stable** Rust.
941///
942/// Applied to a module, this attribute lets you write a single *blanket*
943/// implementation of a trait that provides default behaviour for every type and
944/// then *specialize* that behaviour for specific types. The macro rewrites each
945/// `default` method of the blanket impl into a small runtime dispatcher that
946/// selects the most specific matching implementation by comparing type identity
947/// ([`TypeId`]). The choice is made at run time, though the comparison is between
948/// compile-time constants, so an optimizer may be able to eliminate it when the
949/// concrete type is statically known.
950///
951/// # Usage
952///
953/// Put the trait, the blanket `default` impl, and the specializing impls inside a
954/// module annotated with `#[specialization]`:
955///
956/// ```
957/// use min_specialization::specialization;
958///
959/// #[specialization]
960/// mod size {
961///     pub trait DataSize {
962///         fn size(&self) -> usize;
963///     }
964///
965///     // Blanket default. Methods that may be specialized are marked `default`.
966///     impl<T> DataSize for T {
967///         default fn size(&self) -> usize {
968///             std::mem::size_of::<T>()
969///         }
970///     }
971///
972///     // A specialization overrides the method for a concrete type and must
973///     // *not* repeat the `default` keyword. Borrowed types such as `&str`
974///     // work too — unlike `TypeId::of`, dispatch does not require `'static`.
975///     impl DataSize for &str {
976///         fn size(&self) -> usize {
977///             self.len()
978///         }
979///     }
980/// }
981///
982/// use size::DataSize;
983/// assert_eq!("hello".size(), 5); // specialized: &str -> len()
984/// assert_eq!(0u32.size(), 4);    // blanket default: size_of
985/// ```
986///
987/// # How dispatch is chosen
988///
989/// Each specialization is attached to the blanket impl it refines, and the
990/// generated dispatcher tries them in source order, falling back to the blanket
991/// default when none match. Dispatch is **lifetime-agnostic** — types are
992/// compared with their lifetimes erased — exactly as real `min_specialization`
993/// never dispatches on lifetimes. The dispatch is sound: a branch is taken only
994/// when the runtime type matches, so the internal reinterpretation of `self`,
995/// the arguments, and the return value is always an identity conversion.
996///
997/// # Supported
998///
999/// - Multiple specializations refining one blanket impl.
1000/// - Traits with type parameters (`trait Combine<A, B>`) and lifetime parameters
1001///   (`trait Borrow<'a>`).
1002/// - Associated types and associated consts: they are defined by the blanket
1003///   impl and read by the default method (`Self::Out`, `Self::BYTES`).
1004/// - Generic methods — type, lifetime, and `const` generics, e.g.
1005///   `fn nth<const N: usize>(&self) -> usize`.
1006/// - Generic associated types (GATs), including lifetime and type parameters
1007///   carrying `where` bounds.
1008/// - Specializing on borrowed / non-`'static` types (`&str`, `Holder<'a>`) and on
1009///   a lifetime-bearing trait parameter (`impl<'a> Convert<&'a str> for i32`).
1010/// - Non-trivial argument patterns in methods (`mut x`, `(a, b)`, `_`).
1011///
1012/// # Limitations
1013///
1014/// Unsupported constructs are rejected with a clear, spanned error rather than
1015/// miscompiling. In particular:
1016///
1017/// - **Only methods can be specialized.** A specialization that redefines an
1018///   associated `type` or `const` is an error; the blanket impl's definition is
1019///   shared by every specialization.
1020/// - **A specialization may only override methods the blanket impl marks
1021///   `default`.** Overriding a method that the blanket impl does not define is an
1022///   error.
1023/// - **Overlapping specializations are rejected.** Two specializations for the
1024///   same type produce a `conflicting specializations` error; a full
1025///   specialization *lattice* (e.g. ordering `Vec<i32>` ahead of `Vec<T>`) is not
1026///   modelled.
1027/// - **A specialization must restate the blanket impl's bounds.** Omitting them
1028///   surfaces as an ordinary coherence error (`E0119`).
1029/// - The `default` keyword goes on **methods**, not on the impl itself;
1030///   `default impl`, `default type`, and `default const` are not supported.
1031/// - No const-generic specialization and no fully-generic specializing impls
1032///   (e.g. `impl<U> Tr for Vec<U>`).
1033/// - Do **not** specialize on a specific lifetime (e.g.
1034///   `impl Tr for Cell<&'static str>`); like real `min_specialization`, dispatch
1035///   is lifetime-agnostic and cannot police it.
1036///
1037/// [`min_specialization`]: https://doc.rust-lang.org/unstable-book/language-features/min-specialization.html
1038/// [`TypeId`]: core::any::TypeId
1039#[proc_macro_error]
1040#[proc_macro_attribute]
1041pub fn specialization(_attr: TokenStream1, input: TokenStream1) -> TokenStream1 {
1042    let module = parse_macro_input!(input);
1043    specialization_mod(module).into()
1044}