@@ -3,6 +3,9 @@ use crate::ty::{DefId, DefIdTree};
3
3
use rustc_hir:: CRATE_HIR_ID ;
4
4
use smallvec:: SmallVec ;
5
5
use std:: mem;
6
+ use std:: sync:: Arc ;
7
+
8
+ use DefIdForest :: * ;
6
9
7
10
/// Represents a forest of `DefId`s closed under the ancestor relation. That is,
8
11
/// if a `DefId` representing a module is contained in the forest then all
@@ -11,20 +14,30 @@ use std::mem;
11
14
///
12
15
/// This is used to represent a set of modules in which a type is visibly
13
16
/// 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.
14
21
#[ 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) )
22
35
}
23
36
24
37
impl < ' tcx > DefIdForest {
25
38
/// Creates an empty forest.
26
39
pub fn empty ( ) -> DefIdForest {
27
- DefIdForest { root_ids : SmallVec :: new ( ) }
40
+ DefIdForest :: Empty
28
41
}
29
42
30
43
/// Creates a forest consisting of a single tree representing the entire
@@ -37,19 +50,42 @@ impl<'tcx> DefIdForest {
37
50
38
51
/// Creates a forest containing a `DefId` and all its descendants.
39
52
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
+ }
43
71
}
44
72
45
73
/// Tests whether the forest is empty.
46
74
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 ( )
48
84
}
49
85
50
86
/// Tests whether the forest contains a given DefId.
51
87
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 )
53
89
}
54
90
55
91
/// Calculate the intersection of a collection of forests.
@@ -58,65 +94,50 @@ impl<'tcx> DefIdForest {
58
94
I : IntoIterator < Item = DefIdForest > ,
59
95
{
60
96
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 ( ) )
63
99
} else {
64
100
return DefIdForest :: full ( tcx) ;
65
101
} ;
66
102
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 ( ) ;
69
104
for next_forest in iter {
70
105
// No need to continue if the intersection is already empty.
71
106
if ret. is_empty ( ) {
72
107
break ;
73
108
}
74
109
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) ) ) ;
87
112
// 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) ;
96
116
next_ret. drain ( ..) ;
97
117
}
98
- ret
118
+ DefIdForest :: from_slice ( & ret)
99
119
}
100
120
101
121
/// Calculate the union of a collection of forests.
102
122
pub fn union < I > ( tcx : TyCtxt < ' tcx > , iter : I ) -> DefIdForest
103
123
where
104
124
I : IntoIterator < Item = DefIdForest > ,
105
125
{
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 ( ) ;
108
128
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) {
113
134
next_ret. push ( id) ;
114
135
}
115
136
}
116
137
117
- mem:: swap ( & mut next_ret, & mut ret. root_ids ) ;
138
+ mem:: swap ( & mut next_ret, & mut ret) ;
118
139
next_ret. drain ( ..) ;
119
140
}
120
- ret
141
+ DefIdForest :: from_slice ( & ret)
121
142
}
122
143
}
0 commit comments