@@ -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,20 +14,30 @@ 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- /// its 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
@@ -37,19 +50,42 @@ impl<'tcx> DefIdForest {
3750
3851 /// Creates a forest containing a `DefId` and all its descendants.
3952 pub fn from_id ( id : DefId ) -> DefIdForest {
40- let mut root_ids = SmallVec :: new ( ) ;
41- root_ids. push ( id) ;
42- DefIdForest { root_ids }
53+ DefIdForest :: Single ( id)
54+ }
55+
56+ fn as_slice ( & self ) -> & [ DefId ] {
57+ match self {
58+ Empty => & [ ] ,
59+ Single ( id) => std:: slice:: from_ref ( id) ,
60+ Multiple ( root_ids) => root_ids,
61+ }
62+ }
63+
64+ // Only allocates in the rare `Multiple` case.
65+ fn from_slice ( root_ids : & [ DefId ] ) -> DefIdForest {
66+ match root_ids {
67+ [ ] => Empty ,
68+ [ id] => Single ( * id) ,
69+ _ => DefIdForest :: Multiple ( root_ids. into ( ) ) ,
70+ }
4371 }
4472
4573 /// Tests whether the forest is empty.
4674 pub fn is_empty ( & self ) -> bool {
47- self . root_ids . is_empty ( )
75+ match self {
76+ Empty => true ,
77+ Single ( ..) | Multiple ( ..) => false ,
78+ }
79+ }
80+
81+ /// Iterate over the set of roots.
82+ fn iter ( & self ) -> impl Iterator < Item = DefId > + ' _ {
83+ self . as_slice ( ) . iter ( ) . copied ( )
4884 }
4985
5086 /// Tests whether the forest contains a given DefId.
5187 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 ) )
88+ slice_contains ( tcx, self . as_slice ( ) , id )
5389 }
5490
5591 /// Calculate the intersection of a collection of forests.
@@ -58,65 +94,50 @@ impl<'tcx> DefIdForest {
5894 I : IntoIterator < Item = DefIdForest > ,
5995 {
6096 let mut iter = iter. into_iter ( ) ;
61- let mut ret = if let Some ( first) = iter. next ( ) {
62- first
97+ let mut ret: SmallVec < [ _ ; 1 ] > = if let Some ( first) = iter. next ( ) {
98+ SmallVec :: from_slice ( first. as_slice ( ) )
6399 } else {
64100 return DefIdForest :: full ( tcx) ;
65101 } ;
66102
67- let mut next_ret = SmallVec :: new ( ) ;
68- let mut old_ret: SmallVec < [ DefId ; 1 ] > = SmallVec :: new ( ) ;
103+ let mut next_ret: SmallVec < [ _ ; 1 ] > = SmallVec :: new ( ) ;
69104 for next_forest in iter {
70105 // No need to continue if the intersection is already empty.
71106 if ret. is_empty ( ) {
72107 break ;
73108 }
74109
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-
110+ // We keep the elements in `ret` that are also in `next_forest`.
111+ next_ret. extend ( ret. iter ( ) . copied ( ) . filter ( |& id| next_forest. contains ( tcx, id) ) ) ;
87112 // 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 ) ;
113+ next_ret. extend ( next_forest. iter ( ) . filter ( |& id| slice_contains ( tcx, & ret, id) ) ) ;
114+
115+ mem:: swap ( & mut next_ret, & mut ret) ;
96116 next_ret. drain ( ..) ;
97117 }
98- ret
118+ DefIdForest :: from_slice ( & ret)
99119 }
100120
101121 /// Calculate the union of a collection of forests.
102122 pub fn union < I > ( tcx : TyCtxt < ' tcx > , iter : I ) -> DefIdForest
103123 where
104124 I : IntoIterator < Item = DefIdForest > ,
105125 {
106- let mut ret = DefIdForest :: empty ( ) ;
107- let mut next_ret = SmallVec :: new ( ) ;
126+ let mut ret: SmallVec < [ _ ; 1 ] > = SmallVec :: new ( ) ;
127+ let mut next_ret: SmallVec < [ _ ; 1 ] > = SmallVec :: new ( ) ;
108128 for next_forest in iter {
109- next_ret. extend ( ret. root_ids . drain ( ..) . filter ( |& id| !next_forest. contains ( tcx, id) ) ) ;
110-
111- for id in next_forest. root_ids {
112- if !next_ret. contains ( & id) {
129+ // We add everything in `ret` that is not in `next_forest`.
130+ next_ret. extend ( ret. iter ( ) . copied ( ) . filter ( |& id| !next_forest. contains ( tcx, id) ) ) ;
131+ // We add everything in `next_forest` that we haven't added yet.
132+ for id in next_forest. iter ( ) {
133+ if !slice_contains ( tcx, & next_ret, id) {
113134 next_ret. push ( id) ;
114135 }
115136 }
116137
117- mem:: swap ( & mut next_ret, & mut ret. root_ids ) ;
138+ mem:: swap ( & mut next_ret, & mut ret) ;
118139 next_ret. drain ( ..) ;
119140 }
120- ret
141+ DefIdForest :: from_slice ( & ret)
121142 }
122143}
0 commit comments