| 
1 |  | -use std::collections::BTreeMap;  | 
 | 1 | +use std::collections::{BTreeMap, VecDeque};  | 
2 | 2 | 
 
  | 
3 |  | -use rustc_data_structures::fx::FxIndexMap;  | 
4 |  | -use rustc_errors::Diag;  | 
 | 3 | +use rustc_data_structures::fx::{FxHashSet, FxIndexMap};  | 
5 | 4 | use rustc_hir::def_id::DefId;  | 
6 | 5 | use rustc_infer::infer::InferCtxt;  | 
7 | 6 | pub use rustc_infer::traits::util::*;  | 
8 | 7 | use rustc_middle::bug;  | 
9 | 8 | use rustc_middle::ty::{  | 
10 |  | -    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast,  | 
 | 9 | +    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,  | 
11 | 10 | };  | 
12 | 11 | use rustc_span::Span;  | 
13 | 12 | use smallvec::{SmallVec, smallvec};  | 
14 | 13 | use tracing::debug;  | 
15 | 14 | 
 
  | 
16 |  | -///////////////////////////////////////////////////////////////////////////  | 
17 |  | -// `TraitAliasExpander` iterator  | 
18 |  | -///////////////////////////////////////////////////////////////////////////  | 
19 |  | - | 
20 |  | -/// "Trait alias expansion" is the process of expanding a sequence of trait  | 
21 |  | -/// references into another sequence by transitively following all trait  | 
22 |  | -/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias  | 
23 |  | -/// `trait Foo = Bar + Sync;`, and another trait alias  | 
24 |  | -/// `trait Bar = Read + Write`, then the bounds would expand to  | 
25 |  | -/// `Read + Write + Sync + Send`.  | 
26 |  | -/// Expansion is done via a DFS (depth-first search), and the `visited` field  | 
27 |  | -/// is used to avoid cycles.  | 
28 |  | -pub struct TraitAliasExpander<'tcx> {  | 
29 |  | -    tcx: TyCtxt<'tcx>,  | 
30 |  | -    stack: Vec<TraitAliasExpansionInfo<'tcx>>,  | 
31 |  | -}  | 
32 |  | - | 
33 |  | -/// Stores information about the expansion of a trait via a path of zero or more trait aliases.  | 
34 |  | -#[derive(Debug, Clone)]  | 
35 |  | -pub struct TraitAliasExpansionInfo<'tcx> {  | 
36 |  | -    pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,  | 
37 |  | -}  | 
38 |  | - | 
39 |  | -impl<'tcx> TraitAliasExpansionInfo<'tcx> {  | 
40 |  | -    fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {  | 
41 |  | -        Self { path: smallvec![(trait_ref, span)] }  | 
42 |  | -    }  | 
43 |  | - | 
44 |  | -    /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate  | 
45 |  | -    /// trait aliases.  | 
46 |  | -    pub fn label_with_exp_info(  | 
47 |  | -        &self,  | 
48 |  | -        diag: &mut Diag<'_>,  | 
49 |  | -        top_label: &'static str,  | 
50 |  | -        use_desc: &str,  | 
51 |  | -    ) {  | 
52 |  | -        diag.span_label(self.top().1, top_label);  | 
53 |  | -        if self.path.len() > 1 {  | 
54 |  | -            for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {  | 
55 |  | -                diag.span_label(*sp, format!("referenced here ({use_desc})"));  | 
56 |  | -            }  | 
57 |  | -        }  | 
58 |  | -        if self.top().1 != self.bottom().1 {  | 
59 |  | -            // When the trait object is in a return type these two spans match, we don't want  | 
60 |  | -            // redundant labels.  | 
61 |  | -            diag.span_label(  | 
62 |  | -                self.bottom().1,  | 
63 |  | -                format!("trait alias used in trait object type ({use_desc})"),  | 
64 |  | -            );  | 
65 |  | -        }  | 
66 |  | -    }  | 
67 |  | - | 
68 |  | -    pub fn trait_ref(&self) -> ty::PolyTraitRef<'tcx> {  | 
69 |  | -        self.top().0  | 
70 |  | -    }  | 
71 |  | - | 
72 |  | -    pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {  | 
73 |  | -        self.path.last().unwrap()  | 
74 |  | -    }  | 
75 |  | - | 
76 |  | -    pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {  | 
77 |  | -        self.path.first().unwrap()  | 
78 |  | -    }  | 
79 |  | - | 
80 |  | -    fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {  | 
81 |  | -        let mut path = self.path.clone();  | 
82 |  | -        path.push((trait_ref, span));  | 
83 |  | - | 
84 |  | -        Self { path }  | 
85 |  | -    }  | 
86 |  | -}  | 
87 |  | - | 
 | 15 | +/// Return the trait and projection predicates that come from eagerly expanding the  | 
 | 16 | +/// trait aliases in the list of clauses. For each trait predicate, record a stack  | 
 | 17 | +/// of spans that trace from the user-written trait alias bound. For projection predicates,  | 
 | 18 | +/// just record the span of the projection itself.  | 
 | 19 | +///  | 
 | 20 | +/// For trait aliases, we don't deduplicte the predicates, since we currently do not  | 
 | 21 | +/// consider duplicated traits as a single trait for the purposes of our "one trait principal"  | 
 | 22 | +/// restriction; however, for projections we do deduplicate them.  | 
 | 23 | +///  | 
 | 24 | +/// ```rust,ignore (fails)  | 
 | 25 | +/// trait Bar {}  | 
 | 26 | +/// trait Foo = Bar + Bar;  | 
 | 27 | +///  | 
 | 28 | +/// let not_object_safe: dyn Foo; // bad, two `Bar` principals.  | 
 | 29 | +/// ```  | 
88 | 30 | pub fn expand_trait_aliases<'tcx>(  | 
89 | 31 |     tcx: TyCtxt<'tcx>,  | 
90 |  | -    trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>,  | 
91 |  | -) -> TraitAliasExpander<'tcx> {  | 
92 |  | -    let items: Vec<_> =  | 
93 |  | -        trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect();  | 
94 |  | -    TraitAliasExpander { tcx, stack: items }  | 
95 |  | -}  | 
96 |  | - | 
97 |  | -impl<'tcx> TraitAliasExpander<'tcx> {  | 
98 |  | -    /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`  | 
99 |  | -    /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`.  | 
100 |  | -    /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a  | 
101 |  | -    /// trait alias.  | 
102 |  | -    /// The return value indicates whether `item` should be yielded to the user.  | 
103 |  | -    fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {  | 
104 |  | -        let tcx = self.tcx;  | 
105 |  | -        let trait_ref = item.trait_ref();  | 
106 |  | -        let pred = trait_ref.upcast(tcx);  | 
107 |  | - | 
108 |  | -        debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);  | 
109 |  | - | 
110 |  | -        // Don't recurse if this bound is not a trait alias.  | 
111 |  | -        let is_alias = tcx.is_trait_alias(trait_ref.def_id());  | 
112 |  | -        if !is_alias {  | 
113 |  | -            return true;  | 
114 |  | -        }  | 
115 |  | - | 
116 |  | -        // Don't recurse if this trait alias is already on the stack for the DFS search.  | 
117 |  | -        let anon_pred = anonymize_predicate(tcx, pred);  | 
118 |  | -        if item  | 
119 |  | -            .path  | 
120 |  | -            .iter()  | 
121 |  | -            .rev()  | 
122 |  | -            .skip(1)  | 
123 |  | -            .any(|&(tr, _)| anonymize_predicate(tcx, tr.upcast(tcx)) == anon_pred)  | 
124 |  | -        {  | 
125 |  | -            return false;  | 
126 |  | -        }  | 
127 |  | - | 
128 |  | -        // Get components of trait alias.  | 
129 |  | -        let predicates = tcx.explicit_super_predicates_of(trait_ref.def_id());  | 
130 |  | -        debug!(?predicates);  | 
131 |  | - | 
132 |  | -        let items = predicates.skip_binder().iter().rev().filter_map(|(pred, span)| {  | 
133 |  | -            pred.instantiate_supertrait(tcx, trait_ref)  | 
134 |  | -                .as_trait_clause()  | 
135 |  | -                .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))  | 
136 |  | -        });  | 
137 |  | -        debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>());  | 
138 |  | - | 
139 |  | -        self.stack.extend(items);  | 
140 |  | - | 
141 |  | -        false  | 
142 |  | -    }  | 
143 |  | -}  | 
144 |  | - | 
145 |  | -impl<'tcx> Iterator for TraitAliasExpander<'tcx> {  | 
146 |  | -    type Item = TraitAliasExpansionInfo<'tcx>;  | 
147 |  | - | 
148 |  | -    fn size_hint(&self) -> (usize, Option<usize>) {  | 
149 |  | -        (self.stack.len(), None)  | 
150 |  | -    }  | 
151 |  | - | 
152 |  | -    fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {  | 
153 |  | -        while let Some(item) = self.stack.pop() {  | 
154 |  | -            if self.expand(&item) {  | 
155 |  | -                return Some(item);  | 
 | 32 | +    clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,  | 
 | 33 | +) -> (  | 
 | 34 | +    Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,  | 
 | 35 | +    Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,  | 
 | 36 | +) {  | 
 | 37 | +    let mut trait_preds = vec![];  | 
 | 38 | +    let mut projection_preds = vec![];  | 
 | 39 | +    let mut seen_projection_preds = FxHashSet::default();  | 
 | 40 | + | 
 | 41 | +    let mut queue: VecDeque<_> = clauses.into_iter().map(|(p, s)| (p, smallvec![s])).collect();  | 
 | 42 | + | 
 | 43 | +    while let Some((clause, spans)) = queue.pop_front() {  | 
 | 44 | +        match clause.kind().skip_binder() {  | 
 | 45 | +            ty::ClauseKind::Trait(trait_pred) => {  | 
 | 46 | +                if tcx.is_trait_alias(trait_pred.def_id()) {  | 
 | 47 | +                    queue.extend(  | 
 | 48 | +                        tcx.explicit_super_predicates_of(trait_pred.def_id())  | 
 | 49 | +                            .iter_identity_copied()  | 
 | 50 | +                            .map(|(clause, span)| {  | 
 | 51 | +                                let mut spans = spans.clone();  | 
 | 52 | +                                spans.push(span);  | 
 | 53 | +                                (  | 
 | 54 | +                                    clause.instantiate_supertrait(  | 
 | 55 | +                                        tcx,  | 
 | 56 | +                                        clause.kind().rebind(trait_pred.trait_ref),  | 
 | 57 | +                                    ),  | 
 | 58 | +                                    spans,  | 
 | 59 | +                                )  | 
 | 60 | +                            }),  | 
 | 61 | +                    );  | 
 | 62 | +                } else {  | 
 | 63 | +                    trait_preds.push((clause.kind().rebind(trait_pred), spans));  | 
 | 64 | +                }  | 
156 | 65 |             }  | 
 | 66 | +            ty::ClauseKind::Projection(projection_pred) => {  | 
 | 67 | +                let projection_pred = clause.kind().rebind(projection_pred);  | 
 | 68 | +                if !seen_projection_preds.insert(tcx.anonymize_bound_vars(projection_pred)) {  | 
 | 69 | +                    continue;  | 
 | 70 | +                }  | 
 | 71 | +                projection_preds.push((projection_pred, *spans.last().unwrap()));  | 
 | 72 | +            }  | 
 | 73 | +            ty::ClauseKind::RegionOutlives(..)  | 
 | 74 | +            | ty::ClauseKind::TypeOutlives(..)  | 
 | 75 | +            | ty::ClauseKind::ConstArgHasType(_, _)  | 
 | 76 | +            | ty::ClauseKind::WellFormed(_)  | 
 | 77 | +            | ty::ClauseKind::ConstEvaluatable(_)  | 
 | 78 | +            | ty::ClauseKind::HostEffect(..) => {}  | 
157 | 79 |         }  | 
158 |  | -        None  | 
159 | 80 |     }  | 
 | 81 | + | 
 | 82 | +    (trait_preds, projection_preds)  | 
160 | 83 | }  | 
161 | 84 | 
 
  | 
162 | 85 | ///////////////////////////////////////////////////////////////////////////  | 
 | 
0 commit comments