@@ -3,6 +3,9 @@ use crate::ty::{DefId, DefIdTree};
33use rustc_hir:: CRATE_HIR_ID ;
44use smallvec:: SmallVec ;
55use std:: mem;
6+ use std:: sync:: Arc ;
7+
8+ use DefIdForest :: * ;
69
710/// Represents a forest of `DefId`s closed under the ancestor relation. That is,
811/// if a `DefId` representing a module is contained in the forest then all
@@ -11,45 +14,77 @@ use std::mem;
1114///
1215/// This is used to represent a set of modules in which a type is visibly
1316/// uninhabited.
17+ ///
18+ /// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
19+ /// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
20+ /// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
1421#[ derive( Clone , HashStable ) ]
15- pub struct DefIdForest {
16- /// The minimal set of `DefId`s required to represent the whole set.
17- /// If A and B are DefIds in the `DefIdForest`, and A is a descendant
18- /// of B, then only B will be in `root_ids`.
19- /// We use a `SmallVec` here because (for its use for caching inhabitedness)
20- /// it's rare that this will contain even two IDs.
21- root_ids : SmallVec < [ DefId ; 1 ] > ,
22+ pub enum DefIdForest {
23+ Empty ,
24+ Single ( DefId ) ,
25+ /// This variant is very rare.
26+ /// Invariant: >1 elements
27+ /// We use `Arc` because this is used in the output of a query.
28+ Multiple ( Arc < [ DefId ] > ) ,
29+ }
30+
31+ /// Tests whether a slice of roots contains a given DefId.
32+ #[ inline]
33+ fn slice_contains ( tcx : TyCtxt < ' tcx > , slice : & [ DefId ] , id : DefId ) -> bool {
34+ slice. iter ( ) . any ( |root_id| tcx. is_descendant_of ( id, * root_id) )
2235}
2336
2437impl < ' tcx > DefIdForest {
2538 /// Creates an empty forest.
2639 pub fn empty ( ) -> DefIdForest {
27- DefIdForest { root_ids : SmallVec :: new ( ) }
40+ DefIdForest :: Empty
2841 }
2942
3043 /// Creates a forest consisting of a single tree representing the entire
3144 /// crate.
3245 #[ inline]
3346 pub fn full ( tcx : TyCtxt < ' tcx > ) -> DefIdForest {
34- let crate_id = tcx. hir ( ) . local_def_id ( CRATE_HIR_ID ) ;
35- DefIdForest :: from_id ( crate_id. to_def_id ( ) )
47+ DefIdForest :: from_id ( tcx. hir ( ) . local_def_id ( CRATE_HIR_ID ) . to_def_id ( ) )
3648 }
3749
3850 /// Creates a forest containing a `DefId` and all its descendants.
3951 pub fn from_id ( id : DefId ) -> DefIdForest {
40- let mut root_ids = SmallVec :: new ( ) ;
41- root_ids. push ( id) ;
42- DefIdForest { root_ids }
52+ DefIdForest :: Single ( id)
53+ }
54+
55+ fn as_slice ( & self ) -> & [ DefId ] {
56+ match self {
57+ Empty => & [ ] ,
58+ Single ( id) => std:: slice:: from_ref ( id) ,
59+ Multiple ( root_ids) => root_ids,
60+ }
61+ }
62+
63+ // Only allocates in the rare `Multiple` case.
64+ fn from_slice ( root_ids : & [ DefId ] ) -> DefIdForest {
65+ match root_ids {
66+ [ ] => Empty ,
67+ [ id] => Single ( * id) ,
68+ _ => DefIdForest :: Multiple ( root_ids. into ( ) ) ,
69+ }
4370 }
4471
4572 /// Tests whether the forest is empty.
4673 pub fn is_empty ( & self ) -> bool {
47- self . root_ids . is_empty ( )
74+ match self {
75+ Empty => true ,
76+ Single ( ..) | Multiple ( ..) => false ,
77+ }
78+ }
79+
80+ /// Iterate over the set of roots.
81+ fn iter ( & self ) -> impl Iterator < Item = DefId > + ' _ {
82+ self . as_slice ( ) . iter ( ) . copied ( )
4883 }
4984
5085 /// Tests whether the forest contains a given DefId.
5186 pub fn contains ( & self , tcx : TyCtxt < ' tcx > , id : DefId ) -> bool {
52- self . root_ids . iter ( ) . any ( |root_id| tcx. is_descendant_of ( id , * root_id ) )
87+ slice_contains ( tcx, self . as_slice ( ) , id )
5388 }
5489
5590 /// Calculate the intersection of a collection of forests.
@@ -58,65 +93,55 @@ impl<'tcx> DefIdForest {
5893 I : IntoIterator < Item = DefIdForest > ,
5994 {
6095 let mut iter = iter. into_iter ( ) ;
61- let mut ret = if let Some ( first) = iter. next ( ) {
62- first
96+ let mut ret: SmallVec < [ _ ; 1 ] > = if let Some ( first) = iter. next ( ) {
97+ SmallVec :: from_slice ( first. as_slice ( ) )
6398 } else {
6499 return DefIdForest :: full ( tcx) ;
65100 } ;
66101
67- let mut next_ret = SmallVec :: new ( ) ;
68- let mut old_ret: SmallVec < [ DefId ; 1 ] > = SmallVec :: new ( ) ;
102+ let mut next_ret: SmallVec < [ _ ; 1 ] > = SmallVec :: new ( ) ;
69103 for next_forest in iter {
70104 // No need to continue if the intersection is already empty.
71- if ret. is_empty ( ) {
72- break ;
105+ if ret. is_empty ( ) || next_forest . is_empty ( ) {
106+ return DefIdForest :: empty ( ) ;
73107 }
74108
75- // `next_ret` and `old_ret` are empty here.
76- // We keep the elements in `ret` that are also in `next_forest`. Those that aren't are
77- // put back in `ret` via `old_ret`.
78- for id in ret. root_ids . drain ( ..) {
79- if next_forest. contains ( tcx, id) {
80- next_ret. push ( id) ;
81- } else {
82- old_ret. push ( id) ;
83- }
84- }
85- ret. root_ids . extend ( old_ret. drain ( ..) ) ;
86-
109+ // We keep the elements in `ret` that are also in `next_forest`.
110+ next_ret. extend ( ret. iter ( ) . copied ( ) . filter ( |& id| next_forest. contains ( tcx, id) ) ) ;
87111 // We keep the elements in `next_forest` that are also in `ret`.
88- // You'd think this is not needed because `next_ret` already contains `ret \inter
89- // next_forest`. But those aren't just sets of things. If `ret = [a]`, `next_forest =
90- // [b]` and `b` is a submodule of `a`, then `b` belongs in the intersection but we
91- // didn't catch it in the loop above.
92- next_ret. extend ( next_forest. root_ids . into_iter ( ) . filter ( |& id| ret. contains ( tcx, id) ) ) ;
93- // `next_ret` now contains the intersection of the original `ret` and `next_forest`.
94-
95- mem:: swap ( & mut next_ret, & mut ret. root_ids ) ;
96- next_ret. drain ( ..) ;
112+ next_ret. extend ( next_forest. iter ( ) . filter ( |& id| slice_contains ( tcx, & ret, id) ) ) ;
113+
114+ mem:: swap ( & mut next_ret, & mut ret) ;
115+ next_ret. clear ( ) ;
97116 }
98- ret
117+ DefIdForest :: from_slice ( & ret)
99118 }
100119
101120 /// Calculate the union of a collection of forests.
102121 pub fn union < I > ( tcx : TyCtxt < ' tcx > , iter : I ) -> DefIdForest
103122 where
104123 I : IntoIterator < Item = DefIdForest > ,
105124 {
106- let mut ret = DefIdForest :: empty ( ) ;
107- let mut next_ret = SmallVec :: new ( ) ;
125+ let mut ret: SmallVec < [ _ ; 1 ] > = SmallVec :: new ( ) ;
126+ let mut next_ret: SmallVec < [ _ ; 1 ] > = SmallVec :: new ( ) ;
108127 for next_forest in iter {
109- next_ret. extend ( ret. root_ids . drain ( ..) . filter ( |& id| !next_forest. contains ( tcx, id) ) ) ;
128+ // Union with the empty set is a no-op.
129+ if next_forest. is_empty ( ) {
130+ continue ;
131+ }
110132
111- for id in next_forest. root_ids {
112- if !next_ret. contains ( & id) {
133+ // We add everything in `ret` that is not in `next_forest`.
134+ next_ret. extend ( ret. iter ( ) . copied ( ) . filter ( |& id| !next_forest. contains ( tcx, id) ) ) ;
135+ // We add everything in `next_forest` that we haven't added yet.
136+ for id in next_forest. iter ( ) {
137+ if !slice_contains ( tcx, & next_ret, id) {
113138 next_ret. push ( id) ;
114139 }
115140 }
116141
117- mem:: swap ( & mut next_ret, & mut ret. root_ids ) ;
118- next_ret. drain ( .. ) ;
142+ mem:: swap ( & mut next_ret, & mut ret) ;
143+ next_ret. clear ( ) ;
119144 }
120- ret
145+ DefIdForest :: from_slice ( & ret)
121146 }
122147}
0 commit comments