abi_stable_derive/sabi_trait/
trait_definition.rs

1use super::{
2    attribute_parsing::{MethodWithAttrs, SabiTraitAttrs},
3    impl_interfacetype::{TraitStruct, WhichTrait, TRAIT_LIST},
4    lifetime_unelider::BorrowKind,
5    parse_utils::{parse_str_as_ident, parse_str_as_trait_bound, parse_str_as_type},
6    replace_self_path::{self, ReplaceWith},
7    *,
8};
9
10use crate::{
11    set_span_visitor::SetSpanVisitor,
12    utils::{dummy_ident, LinearResult, SynResultExt},
13};
14
15use as_derive_utils::{return_spanned_err, spanned_err, syn_err};
16
17use std::{
18    collections::{HashMap, HashSet},
19    iter,
20};
21
22use core_extensions::{matches, IteratorExt};
23
24use syn::{
25    punctuated::Punctuated,
26    spanned::Spanned,
27    token::Unsafe,
28    token::{Colon, Comma, Semi},
29    visit_mut::VisitMut,
30    Abi, Attribute, Block, FnArg, Ident, ItemTrait, Lifetime, LifetimeDef, TraitItem,
31    TypeParamBound, WherePredicate,
32};
33
34use proc_macro2::Span;
35
36#[derive(Debug, Clone)]
37pub struct AssocTyWithIndex {
38    pub index: usize,
39    pub assoc_ty: syn::TraitItemType,
40}
41
42////////////////////////////////////////////////////////////////////////////////
43
44/// Represents a trait for use in `#[sabi_trait]`.
45#[derive(Debug, Clone)]
46pub(crate) struct TraitDefinition<'a> {
47    pub(crate) item: &'a ItemTrait,
48    /// The name of the trait.
49    pub(crate) name: &'a Ident,
50    /// What type to use the backend for the trait object,DynTrait or RObject.
51    pub(crate) which_object: WhichObject,
52    /// The where predicates in the where clause of the trait,
53    /// if it doesn't have one this is empty.
54    pub(crate) where_preds: Punctuated<WherePredicate, Comma>,
55    /// Attributes applied to the vtable.
56    pub(crate) derive_attrs: &'a [Attribute],
57    /// Attributes applied to the trait.
58    pub(crate) other_attrs: &'a [Attribute],
59    pub(crate) generics: &'a syn::Generics,
60    /// The `Iterator::Item` type for this trait,
61    /// None if it doesn't have Iterator as a supertrait.
62    pub(crate) iterator_item: Option<&'a syn::Type>,
63    #[allow(dead_code)]
64    /// The path for the implemented serde::Deserialize trait
65    /// (it may reference some trait lifetime parameter)
66    pub(crate) deserialize_bound: Option<DeserializeBound>,
67    /// The traits this has as supertraits.
68    pub(crate) impld_traits: Vec<TraitImplness<'a>>,
69    /// The traits this doesn't have as supertraits.
70    pub(crate) unimpld_traits: Vec<&'a Ident>,
71    /// A struct describing the traits this does and doesn't have as supertraits
72    /// (true means implemented,false means unimplemented)
73    pub(crate) trait_flags: TraitStruct<bool>,
74    /// The region of code of the identifiers for the supertraits,
75    /// with `Span::call_site()` for the ones that aren't supertraits.
76    pub(crate) trait_spans: TraitStruct<Span>,
77    /// The lifetimes declared in the trait generic parameter list that are used in
78    /// `&'lifetime self` `&'lifetime mut self` method receivers,
79    /// or used directly as supertraits.
80    pub(crate) lifetime_bounds: Punctuated<&'a Lifetime, Comma>,
81    /// The visibility of the trait.
82    pub(crate) vis: VisibilityKind<'a>,
83    /// The visibility of the trait,inside a submodule.
84    pub(crate) submod_vis: RelativeVis<'a>,
85    // The keys use the proginal identifier for the associated type.
86    pub(crate) assoc_tys: HashMap<&'a Ident, AssocTyWithIndex>,
87    ///
88    pub(crate) methods: Vec<TraitMethod<'a>>,
89    /// Whether this has by mutable reference methods.
90    pub(crate) has_mut_methods: bool,
91    /// Whether this has by-value methods.
92    pub(crate) has_val_methods: bool,
93    /// Disables `ìmpl Trait for Trait_TO`
94    pub(crate) disable_trait_impl: bool,
95    /// Whether this has `'static` as a supertrait syntactically.
96    pub(crate) is_static: IsStaticTrait,
97    /// A TokenStream with the equivalent of `<Pointer::PtrTarget as Trait>::`
98    pub(crate) ts_fq_self: &'a TokenStream2,
99    pub(crate) ctokens: &'a CommonTokens,
100}
101
102////////////////////////////////////////////////////////////////////////////////
103
104impl<'a> TraitDefinition<'a> {
105    pub(super) fn new(
106        trait_: &'a ItemTrait,
107        SabiTraitAttrs {
108            attrs,
109            methods_with_attrs,
110            which_object,
111            disable_trait_impl,
112            disable_inherent_default,
113            ..
114        }: SabiTraitAttrs<'a>,
115        arenas: &'a Arenas,
116        ctokens: &'a CommonTokens,
117    ) -> Result<Self, syn::Error> {
118        let vis = VisibilityKind::new(&trait_.vis);
119        let submod_vis = vis.submodule_level(1);
120        let mut assoc_tys = HashMap::default();
121        let mut methods = Vec::<TraitMethod<'a>>::new();
122
123        let mut errors = LinearResult::ok(());
124
125        methods_with_attrs
126            .into_iter()
127            .zip(disable_inherent_default)
128            .filter_map(|(func, disable_inh_def)| {
129                match TraitMethod::new(func, disable_inh_def, ctokens, arenas) {
130                    Ok(x) => x,
131                    Err(e) => {
132                        errors.push_err(e);
133                        None
134                    }
135                }
136            })
137            .extending(&mut methods);
138
139        /////////////////////////////////////////////////////
140        ////         Processing the supertrait bounds
141
142        let mut is_static = IsStaticTrait::No;
143
144        let lifetime_params: HashSet<&'a Lifetime> = trait_
145            .generics
146            .lifetimes()
147            .map(|l| &l.lifetime)
148            .chain(iter::once(&ctokens.static_lifetime))
149            .collect();
150
151        let GetSupertraits {
152            impld_traits,
153            unimpld_traits,
154            mut lifetime_bounds,
155            iterator_item,
156            deserialize_bound,
157            trait_flags,
158            trait_spans,
159            errors: supertrait_errors,
160        } = get_supertraits(
161            &trait_.supertraits,
162            &lifetime_params,
163            which_object,
164            arenas,
165            ctokens,
166        );
167        errors.combine_err(supertrait_errors.into());
168
169        // Adding the lifetime parameters in `&'a self` and `&'a mut self`
170        // that were declared in the trait generic parameter list.
171        // This is done because those lifetime bounds are enforced as soon as
172        // the vtable is created,instead of when the methods are called
173        // (it's enforced in method calls in regular trait objects).
174        for method in &methods {
175            if let SelfParam::ByRef {
176                lifetime: Some(lt), ..
177            } = method.self_param
178            {
179                if lifetime_params.contains(lt) {
180                    lifetime_bounds.push(lt);
181                }
182            }
183        }
184
185        for lt in &lifetime_bounds {
186            if lt.ident == "static" {
187                is_static = IsStaticTrait::Yes;
188            }
189        }
190        /////////////////////////////////////////////////////
191
192        let mut assoc_ty_index = 0;
193        for item in &trait_.items {
194            match item {
195                TraitItem::Method { .. } => {}
196                TraitItem::Type(assoc_ty) => {
197                    let with_index = AssocTyWithIndex {
198                        index: assoc_ty_index,
199                        assoc_ty: assoc_ty.clone(),
200                    };
201                    assoc_tys.insert(&assoc_ty.ident, with_index);
202
203                    assoc_ty_index += 1;
204                }
205                item => errors.push_err(spanned_err!(
206                    item,
207                    "Associated item not compatible with #[sabi_trait]",
208                )),
209            }
210        }
211
212        let has_mut_methods = methods.iter().any(|m| {
213            matches!(
214                &m.self_param,
215                SelfParam::ByRef {
216                    is_mutable: true,
217                    ..
218                }
219            )
220        });
221
222        let has_val_methods = methods
223            .iter()
224            .any(|m| matches!(&m.self_param, SelfParam::ByVal));
225
226        let ts_fq_self = {
227            let (_, generics_params, _) = trait_.generics.split_for_impl();
228            quote!( <_OrigPtr::PtrTarget as __Trait #generics_params >:: )
229        };
230
231        errors.into_result()?;
232
233        Ok(TraitDefinition {
234            item: trait_,
235            name: &trait_.ident,
236            which_object,
237            where_preds: trait_
238                .generics
239                .where_clause
240                .as_ref()
241                .map(|wc| wc.predicates.clone())
242                .unwrap_or_default(),
243            derive_attrs: arenas.alloc(attrs.derive_attrs),
244            other_attrs: arenas.alloc(attrs.other_attrs),
245            generics: &trait_.generics,
246            lifetime_bounds,
247            iterator_item,
248            deserialize_bound,
249            impld_traits,
250            unimpld_traits,
251            trait_flags,
252            trait_spans,
253            vis,
254            submod_vis,
255            assoc_tys,
256            methods,
257            has_mut_methods,
258            has_val_methods,
259            disable_trait_impl,
260            ts_fq_self: arenas.alloc(ts_fq_self),
261            is_static,
262            ctokens,
263        })
264    }
265
266    /// Returns a clone of `self`,
267    /// where usages of associated types are replaced for use in `which_item`.
268    pub fn replace_self(&self, which_item: WhichItem) -> Result<Self, syn::Error> {
269        let mut this = self.clone();
270
271        let ctokens = self.ctokens;
272
273        let mut errors = LinearResult::ok(());
274
275        let replace_with = match which_item {
276            WhichItem::Trait | WhichItem::TraitImpl => {
277                return Ok(this);
278            }
279            WhichItem::TraitObjectImpl => ReplaceWith::Remove,
280            WhichItem::VtableDecl => ReplaceWith::Remove,
281            WhichItem::VtableImpl => ReplaceWith::Ident(ctokens.u_capself.clone()),
282        };
283
284        let is_assoc_type = |ident: &Ident| {
285            if self.assoc_tys.contains_key(ident) {
286                Some(ReplaceWith::Keep)
287            } else {
288                None
289            }
290        };
291
292        for where_pred in &mut this.where_preds {
293            replace_self_path::replace_self_path(where_pred, replace_with.clone(), is_assoc_type)
294                .combine_into_err(&mut errors);
295        }
296
297        for assoc_ty in this.assoc_tys.values_mut() {
298            replace_self_path::replace_self_path(
299                &mut assoc_ty.assoc_ty,
300                replace_with.clone(),
301                is_assoc_type,
302            )
303            .combine_into_err(&mut errors);
304        }
305
306        for method in &mut this.methods {
307            method
308                .replace_self(replace_with.clone(), is_assoc_type)
309                .combine_into_err(&mut errors);
310        }
311        errors.into_result().map(|_| this)
312    }
313
314    /// Returns a tokenizer for the generic parameters in this trait.
315    ///
316    /// # Parameters
317    ///
318    /// - `in_what`:
319    ///     Determines where the generic parameters are printed.
320    ///     Eg:impl headers,trait declaration,trait usage.
321    ///
322    /// - `with_assoc_tys`:
323    ///     Whether associated types are printed,and how.
324    ///
325    /// - `after_lifetimes`:
326    ///     What will be printed after lifetime parameters.
327    ///
328    pub fn generics_tokenizer(
329        &self,
330        in_what: InWhat,
331        with_assoc_tys: WithAssocTys,
332        after_lifetimes: &'a TokenStream2,
333    ) -> GenericsTokenizer<'_> {
334        let ctokens = self.ctokens;
335        GenericsTokenizer {
336            gen_params_in: GenParamsIn::with_after_lifetimes(
337                self.generics,
338                in_what,
339                after_lifetimes,
340            ),
341            assoc_tys: match with_assoc_tys {
342                WithAssocTys::Yes(WhichSelf::Regular) => {
343                    Some((&self.assoc_tys, &ctokens.ts_self_colon2))
344                }
345                WithAssocTys::Yes(WhichSelf::Underscore) => {
346                    Some((&self.assoc_tys, &ctokens.ts_uself_colon2))
347                }
348                WithAssocTys::Yes(WhichSelf::FullyQualified) => {
349                    Some((&self.assoc_tys, self.ts_fq_self))
350                }
351                WithAssocTys::Yes(WhichSelf::NoSelf) => Some((&self.assoc_tys, &ctokens.empty_ts)),
352                WithAssocTys::No => None,
353            },
354        }
355    }
356
357    /// Returns the where predicates for the erased pointer type of the ffi-safe trait object.
358    ///
359    /// Example erased pointer types:`RBox<()>`,`RArc<()>`,`&()`,`&mut ()`
360    ///
361    pub fn erased_ptr_preds(&self) -> &'a TokenStream2 {
362        let ctokens = self.ctokens;
363        match (self.has_mut_methods, self.has_val_methods) {
364            (false, false) => &ctokens.ptr_ref_bound,
365            (false, true) => &ctokens.ptr_ref_val_bound,
366            (true, false) => &ctokens.ptr_mut_bound,
367            (true, true) => &ctokens.ptr_mut_val_bound,
368        }
369    }
370
371    /// Returns the where predicates of the inherent implementation of
372    /// the ffi-safe trait object.
373    pub fn trait_impl_where_preds(&self) -> Result<Punctuated<WherePredicate, Comma>, syn::Error> {
374        let mut where_preds = self.where_preds.clone();
375        let mut errors = LinearResult::ok(());
376        for where_pred in &mut where_preds {
377            replace_self_path::replace_self_path(where_pred, ReplaceWith::Remove, |ident| {
378                self.assoc_tys.get(ident).map(|_| ReplaceWith::Remove)
379            })
380            .combine_into_err(&mut errors);
381        }
382        errors.into_result().map(|_| where_preds)
383    }
384
385    /// Returns a tokenizer that outputs the method definitions inside the `which_item` item.
386    pub fn methods_tokenizer(&self, which_item: WhichItem) -> MethodsTokenizer<'_> {
387        MethodsTokenizer {
388            trait_def: self,
389            which_item,
390        }
391    }
392}
393
394////////////////////////////////////////////////////////////////////////////////
395
396/// Represents a trait method for use in `#[sabi_trait]`.
397#[derive(Debug, Clone)]
398pub(crate) struct TraitMethod<'a> {
399    pub(crate) disable_inherent_default: bool,
400    pub(crate) unsafety: Option<&'a Unsafe>,
401    pub(crate) abi: Option<&'a Abi>,
402    /// Attributes applied to the method in the vtable.
403    pub(crate) derive_attrs: &'a [Attribute],
404    /// Attributes applied to the method in the trait definition.
405    pub(crate) other_attrs: &'a [Attribute],
406    /// The name of the method.
407    pub(crate) name: &'a Ident,
408    pub(crate) self_param: SelfParam<'a>,
409    /// The lifetime parameters of this method.
410    pub(crate) lifetimes: Vec<&'a LifetimeDef>,
411    pub(crate) params: Vec<MethodParam<'a>>,
412    /// The return type of this method,if None this returns `()`.
413    pub(crate) output: Option<syn::Type>,
414
415    /// Whether the return type borrows from self
416    pub(crate) return_borrow_kind: Option<BorrowKind>,
417
418    pub(crate) where_clause: MethodWhereClause<'a>,
419    /// The default implementation of the method.
420    pub(crate) default: Option<DefaultMethod<'a>>,
421    /// The semicolon token for the method
422    /// (when the method did not have a default implementation).
423    pub(crate) semicolon: Option<&'a Semi>,
424}
425
426#[derive(Debug, Clone)]
427pub(crate) struct DefaultMethod<'a> {
428    pub(crate) block: &'a Block,
429}
430
431#[derive(Debug, Clone, PartialEq, Eq)]
432pub(crate) struct MethodParam<'a> {
433    /// The name of the method parameter,
434    /// which is `param_<number_of_parameter>` if the parameter is not just an identifier
435    /// (ie:`(left,right)`,`Rect3D{x,y,z}`)
436    pub(crate) name: &'a Ident,
437    /// The parameter type.
438    pub(crate) ty: syn::Type,
439    /// The pattern for the parameter
440    pub(crate) pattern: &'a syn::Pat,
441}
442
443impl<'a> TraitMethod<'a> {
444    pub fn new(
445        mwa: MethodWithAttrs<'a>,
446        disable_inherent_default: bool,
447        ctokens: &'a CommonTokens,
448        arena: &'a Arenas,
449    ) -> Result<Option<Self>, syn::Error> {
450        let method_signature = &mwa.item.sig;
451        let decl = method_signature;
452        let name = &method_signature.ident;
453
454        let mut errors = LinearResult::ok(());
455
456        let push_error_msg = |errors: &mut Result<(), syn::Error>| {
457            errors.push_err(spanned_err!(
458                method_signature.ident,
459                "Cannot define #[sabi_trait]traits containing methods \
460                 without a `self`/`&self`/`&mut self` receiver (static methods)."
461            ));
462        };
463        if decl.inputs.is_empty() {
464            push_error_msg(&mut errors);
465        }
466
467        let mut input_iter = decl.inputs.iter();
468
469        let mut self_param = match input_iter.next() {
470            Some(FnArg::Receiver(receiver)) => match &receiver.reference {
471                Some((_, lifetime)) => SelfParam::ByRef {
472                    lifetime: lifetime.as_ref(),
473                    is_mutable: receiver.mutability.is_some(),
474                },
475                None => SelfParam::ByVal,
476            },
477            Some(FnArg::Typed { .. }) => {
478                push_error_msg(&mut errors);
479                SelfParam::ByVal
480            }
481            None => {
482                push_error_msg(&mut errors);
483                return errors.into_result().map(|_| unreachable!());
484            }
485        };
486
487        let mut lifetimes: Vec<&'a syn::LifetimeDef> = decl.generics.lifetimes().collect();
488
489        let mut return_borrow_kind = None::<BorrowKind>;
490
491        let output = match &decl.output {
492            syn::ReturnType::Default => None,
493            syn::ReturnType::Type(_, ty) => {
494                let mut ty: syn::Type = (**ty).clone();
495                if let SelfParam::ByRef { lifetime, .. } = &mut self_param {
496                    let visit_data = LifetimeUnelider::new(lifetime).visit_type(&mut ty);
497
498                    return_borrow_kind = visit_data.found_borrow_kind;
499
500                    if let Some(lt) = visit_data.additional_lifetime_def {
501                        lifetimes.push(lt);
502                    }
503                }
504                Some(ty)
505            }
506        };
507
508        let default = mwa
509            .item
510            .default
511            .as_ref()
512            .map(|block| DefaultMethod { block });
513
514        let where_clause = decl
515            .generics
516            .where_clause
517            .as_ref()
518            .and_then(|wc| match MethodWhereClause::new(wc, ctokens) {
519                Ok(x) => Some(x),
520                Err(e) => {
521                    errors.push_err(e);
522                    None
523                }
524            })
525            .unwrap_or_default();
526
527        let mut params = Vec::<MethodParam<'a>>::with_capacity(input_iter.len());
528
529        for (param_i, param) in input_iter.enumerate() {
530            let (pattern, ty) = match param {
531                FnArg::Receiver { .. } => unreachable!(),
532                FnArg::Typed(typed) => (&*typed.pat, &*typed.ty),
533            };
534
535            let name = format!("param_{}", param_i);
536            let mut name = syn::parse_str::<Ident>(&name).unwrap_or_else(|e| {
537                errors.push_err(e);
538                dummy_ident()
539            });
540            name.set_span(param.span());
541
542            params.push(MethodParam {
543                name: arena.alloc(name),
544                ty: ty.clone(),
545                pattern,
546            });
547        }
548
549        errors.into_result()?;
550
551        Ok(Some(Self {
552            disable_inherent_default,
553            unsafety: method_signature.unsafety.as_ref(),
554            abi: method_signature.abi.as_ref(),
555            derive_attrs: arena.alloc(mwa.attrs.derive_attrs),
556            other_attrs: arena.alloc(mwa.attrs.other_attrs),
557            name,
558            lifetimes,
559            self_param,
560            params,
561            output,
562            return_borrow_kind,
563            where_clause,
564            default,
565            semicolon: mwa.item.semi_token.as_ref(),
566        }))
567    }
568
569    /// Returns a clone of `self`,
570    /// where usages of associated types are replaced for use in `which_item`.
571    ///
572    /// Whether `Self::AssocTy` is an associated type is determined using `is_assoc_type`,
573    /// which returns `Some()` with what to do with the associated type.
574    pub fn replace_self<F>(
575        &mut self,
576        replace_with: ReplaceWith,
577        mut is_assoc_type: F,
578    ) -> Result<(), syn::Error>
579    where
580        F: FnMut(&Ident) -> Option<ReplaceWith>,
581    {
582        let mut errors = LinearResult::ok(());
583
584        for param in self
585            .params
586            .iter_mut()
587            .map(|x| &mut x.ty)
588            .chain(self.output.as_mut())
589        {
590            replace_self_path::replace_self_path(param, replace_with.clone(), &mut is_assoc_type)
591                .combine_into_err(&mut errors);
592        }
593        errors.into()
594    }
595}
596
597////////////////////////////////////////////////////////////////////////////////
598
599/// Used to print the generic parameters of a trait,
600/// potentially including its associated types.
601#[derive(Debug, Copy, Clone)]
602pub struct GenericsTokenizer<'a> {
603    gen_params_in: GenParamsIn<'a, &'a TokenStream2>,
604    assoc_tys: Option<(&'a HashMap<&'a Ident, AssocTyWithIndex>, &'a TokenStream2)>,
605}
606
607impl<'a> GenericsTokenizer<'a> {
608    /// Changes type parameters to have a `?Sized` bound.
609    #[allow(dead_code)]
610    pub fn set_unsized_types(&mut self) {
611        self.gen_params_in.set_unsized_types();
612    }
613    /// Removes bounds on type parameters.
614    pub fn set_no_bounds(&mut self) {
615        self.gen_params_in.set_no_bounds();
616    }
617    pub fn skip_lifetimes(&mut self) {
618        self.gen_params_in.skip_lifetimes();
619    }
620    #[allow(dead_code)]
621    pub fn skip_consts(&mut self) {
622        self.gen_params_in.skip_consts();
623    }
624}
625
626impl<'a> ToTokens for GenericsTokenizer<'a> {
627    fn to_tokens(&self, ts: &mut TokenStream2) {
628        let with_bounds = self.gen_params_in.outputs_bounds();
629        let with_default = self.gen_params_in.in_what == InWhat::ItemDecl;
630
631        let unsized_types = self.gen_params_in.are_types_unsized();
632
633        let in_dummy_struct = self.gen_params_in.in_what == InWhat::DummyStruct;
634
635        let skips_unbounded = self.gen_params_in.skips_unbounded();
636
637        self.gen_params_in.to_tokens(ts);
638        if let Some((assoc_tys, self_tokens)) = self.assoc_tys {
639            for with_index in assoc_tys.values() {
640                let assoc_ty = &with_index.assoc_ty;
641
642                if skips_unbounded && assoc_ty.bounds.is_empty() {
643                    continue;
644                }
645
646                self_tokens.to_tokens(ts);
647
648                if in_dummy_struct {
649                    use syn::token::{Const, Star};
650                    Star::default().to_tokens(ts);
651                    Const::default().to_tokens(ts);
652                }
653
654                assoc_ty.ident.to_tokens(ts);
655
656                let colon_token = assoc_ty.colon_token.filter(|_| with_bounds);
657
658                if unsized_types {
659                    if colon_token.is_none() {
660                        Colon::default().to_tokens(ts);
661                    }
662                    quote!(?Sized+).to_tokens(ts);
663                }
664                if let Some(colon_token) = colon_token {
665                    colon_token.to_tokens(ts);
666                    assoc_ty.bounds.to_tokens(ts);
667                }
668
669                match &assoc_ty.default {
670                    Some((eq_token, default_ty)) if with_default => {
671                        eq_token.to_tokens(ts);
672                        default_ty.to_tokens(ts);
673                    }
674                    _ => {}
675                }
676
677                Comma::default().to_tokens(ts);
678            }
679        }
680    }
681}
682
683////////////////////////////////////////////////////////////////////////////////
684
685/// Represents a `Deserialize<'de>` supertrait bound.
686#[derive(Debug, Clone)]
687pub(crate) struct DeserializeBound;
688
689/// Used to returns the information about supertraits,to construct TraitDefinition.
690struct GetSupertraits<'a> {
691    impld_traits: Vec<TraitImplness<'a>>,
692    unimpld_traits: Vec<&'a Ident>,
693    lifetime_bounds: Punctuated<&'a Lifetime, Comma>,
694    iterator_item: Option<&'a syn::Type>,
695    deserialize_bound: Option<DeserializeBound>,
696    trait_flags: TraitStruct<bool>,
697    trait_spans: TraitStruct<Span>,
698    errors: LinearResult<()>,
699}
700
701/// Contains information about a supertrait,including whether it's implemented.
702#[derive(Debug, Clone)]
703pub(crate) struct TraitImplness<'a> {
704    pub(crate) ident: Ident,
705    pub(crate) bound: syn::TraitBound,
706    pub(crate) is_implemented: bool,
707    pub(crate) _marker: PhantomData<&'a ()>,
708}
709
710/// Processes the supertrait bounds of a trait definition.
711fn get_supertraits<'a, I>(
712    supertraits: I,
713    lifetime_params: &HashSet<&'a Lifetime>,
714    which_object: WhichObject,
715    arenas: &'a Arenas,
716    _ctokens: &'a CommonTokens,
717) -> GetSupertraits<'a>
718where
719    I: IntoIterator<Item = &'a TypeParamBound>,
720{
721    let trait_map = TRAIT_LIST
722        .iter()
723        .map(|t| (parse_str_as_ident(t.name), t.which_trait))
724        .collect::<HashMap<Ident, WhichTrait>>();
725
726    // A struct indexable by `WhichTrait`,
727    // with information about all possible supertraits.
728    let mut trait_struct = TraitStruct::TRAITS.map(|_, t| TraitImplness {
729        ident: parse_str_as_ident(t.name),
730        bound: parse_str_as_trait_bound(t.full_path).expect("BUG"),
731        is_implemented: false,
732        _marker: PhantomData,
733    });
734
735    let mut lifetime_bounds = Punctuated::<&'a Lifetime, Comma>::new();
736    let mut iterator_item = None;
737    let mut errors = LinearResult::ok(());
738    let deserialize_bound = None;
739
740    for supertrait_bound in supertraits {
741        match supertrait_bound {
742            TypeParamBound::Trait(trait_bound) => {
743                let last_path_component = match trait_bound.path.segments.last() {
744                    Some(x) => x,
745                    None => continue,
746                };
747                let trait_ident = &last_path_component.ident;
748
749                match trait_map.get(trait_ident) {
750                    Some(&which_trait) => {
751                        let usable_by = which_trait.usable_by();
752                        match which_object {
753                            WhichObject::DynTrait if !usable_by.dyn_trait() => {
754                                errors.push_err(spanned_err!(
755                                    trait_bound.path,
756                                    "cannot use this trait with DynTrait",
757                                ));
758                            }
759                            WhichObject::RObject if !usable_by.robject() => {
760                                errors.push_err(spanned_err!(
761                                    trait_bound.path,
762                                    "cannot use this trait with RObject.
763                                     To make that trait usable you must use the \
764                                     #[sabi(use_dyntrait)] attribute,\
765                                     which changes the trait object implementation \
766                                     from using RObject to using DynTrait.\n\
767                                    ",
768                                ));
769                            }
770                            WhichObject::DynTrait | WhichObject::RObject => {}
771                        }
772
773                        fn set_impld(wtrait: &mut TraitImplness<'_>, span: Span) {
774                            wtrait.is_implemented = true;
775                            wtrait.ident.set_span(span);
776                            SetSpanVisitor::new(span).visit_trait_bound_mut(&mut wtrait.bound);
777                        }
778
779                        let span = trait_bound.span();
780
781                        set_impld(&mut trait_struct[which_trait], span);
782
783                        match which_trait {
784                            WhichTrait::Iterator | WhichTrait::DoubleEndedIterator => {
785                                set_impld(&mut trait_struct.iterator, span);
786
787                                let iter_item = extract_iterator_item(last_path_component, arenas);
788                                iterator_item = iterator_item.or(iter_item);
789                            }
790                            WhichTrait::Deserialize => {
791                                errors.push_err(spanned_err!(
792                                    trait_bound.path,
793                                    "Deserialize is not currently supported."
794                                ));
795                            }
796                            WhichTrait::Serialize => {
797                                errors.push_err(spanned_err!(
798                                    trait_bound.path,
799                                    "Serialize is not currently supported."
800                                ));
801                            }
802                            WhichTrait::Eq | WhichTrait::PartialOrd => {
803                                set_impld(&mut trait_struct.partial_eq, span);
804                            }
805                            WhichTrait::Ord => {
806                                set_impld(&mut trait_struct.partial_eq, span);
807                                set_impld(&mut trait_struct.eq, span);
808                                set_impld(&mut trait_struct.partial_ord, span);
809                            }
810                            WhichTrait::IoBufRead => {
811                                set_impld(&mut trait_struct.io_read, span);
812                            }
813                            WhichTrait::Error => {
814                                set_impld(&mut trait_struct.display, span);
815                                set_impld(&mut trait_struct.debug, span);
816                            }
817                            _ => {}
818                        }
819                    }
820                    None => {
821                        let list = trait_map
822                            .keys()
823                            .map(|x| x.to_string())
824                            .collect::<Vec<String>>();
825
826                        errors.push_err(spanned_err!(
827                            supertrait_bound,
828                            "Unexpected supertrait bound.\nExpected one of:\n{}",
829                            list.join("/"),
830                        ));
831                        break;
832                    }
833                }
834            }
835            TypeParamBound::Lifetime(lt) => {
836                if lifetime_params.contains(lt) {
837                    lifetime_bounds.push(lt);
838                } else {
839                    errors.push_err(spanned_err!(
840                        lt,
841                        "Lifetimes is not from the trait or `'static`.",
842                    ));
843                    break;
844                }
845            }
846        };
847    }
848
849    let iter_trait = &mut trait_struct.iterator;
850    let de_iter_trait = &mut trait_struct.double_ended_iterator;
851    if iter_trait.is_implemented || de_iter_trait.is_implemented {
852        let iter_item: syn::Type = iterator_item.cloned().unwrap_or_else(|| {
853            let span = if de_iter_trait.is_implemented {
854                de_iter_trait.ident.span()
855            } else {
856                iter_trait.ident.span()
857            };
858            errors.push_err(syn_err!(span, "You must specify the Iterator item type."));
859            parse_str_as_type("()").expect("BUG")
860        });
861        let path_args = type_as_iter_path_arguments(iter_item);
862
863        fn set_last_arguments(bounds: &mut syn::TraitBound, path_args: syn::PathArguments) {
864            bounds.path.segments.last_mut().expect("BUG").arguments = path_args;
865        }
866
867        if de_iter_trait.is_implemented {
868            set_last_arguments(&mut de_iter_trait.bound, path_args.clone());
869        }
870        set_last_arguments(&mut iter_trait.bound, path_args);
871    }
872
873    let mut impld_traits = Vec::new();
874    let mut unimpld_traits = Vec::new();
875    let trait_flags = trait_struct.as_ref().map(|_, x| x.is_implemented);
876    let trait_spans = trait_struct.as_ref().map(|_, x| x.ident.span());
877
878    for trait_ in trait_struct.to_vec() {
879        if trait_.is_implemented {
880            impld_traits.push(trait_);
881        } else {
882            unimpld_traits.push(arenas.alloc(trait_.ident.clone()));
883        }
884    }
885
886    GetSupertraits {
887        impld_traits,
888        unimpld_traits,
889        lifetime_bounds,
890        iterator_item,
891        deserialize_bound,
892        trait_flags,
893        trait_spans,
894        errors,
895    }
896}
897
898////////////////////////////////////////////////////////////////////////////////
899
900/// Extracts the Iterator::Item out of a path component.
901fn extract_iterator_item<'a>(
902    last_path_component: &syn::PathSegment,
903    arenas: &'a Arenas,
904) -> Option<&'a syn::Type> {
905    use syn::{GenericArgument, PathArguments};
906
907    let angle_brackets = match &last_path_component.arguments {
908        PathArguments::AngleBracketed(x) => x,
909        _ => return None,
910    };
911
912    for gen_arg in &angle_brackets.args {
913        match gen_arg {
914            GenericArgument::Binding(bind) if bind.ident == "Item" => {
915                return Some(arenas.alloc(bind.ty.clone()));
916            }
917            _ => {}
918        }
919    }
920    None
921}
922
923/// Converts a type to `<Item= ty >`.
924fn type_as_iter_path_arguments(ty: syn::Type) -> syn::PathArguments {
925    let x = syn::Binding {
926        ident: parse_str_as_ident("Item"),
927        eq_token: Default::default(),
928        ty,
929    };
930
931    let x = syn::GenericArgument::Binding(x);
932
933    let x = syn::AngleBracketedGenericArguments {
934        colon2_token: None,
935        lt_token: Default::default(),
936        args: iter::once(x).collect(),
937        gt_token: Default::default(),
938    };
939
940    syn::PathArguments::AngleBracketed(x)
941}
942
943/// Extracts the lifetime in `Deserialize<'lt>` out of a path component.
944#[allow(dead_code)]
945fn extract_deserialize_lifetime<'a>(
946    last_path_component: &syn::PathSegment,
947    arenas: &'a Arenas,
948) -> Result<&'a syn::Lifetime, syn::Error> {
949    use syn::{GenericArgument, PathArguments};
950
951    let angle_brackets = match &last_path_component.arguments {
952        PathArguments::AngleBracketed(x) => x,
953        _ => return_spanned_err!(last_path_component, "Expected a lifetime parameter inside"),
954    };
955
956    for gen_arg in &angle_brackets.args {
957        if let GenericArgument::Lifetime(lt) = gen_arg {
958            return Ok(arenas.alloc(lt.clone()));
959        }
960    }
961    Err(spanned_err!(
962        last_path_component,
963        "Expected a lifetime parameter inside"
964    ))
965}