@@ -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,45 +14,77 @@ 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.
14
- #[ derive( Clone ) ]
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 ] > ,
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.
21
+ #[ derive( Clone , HashStable ) ]
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
31
44
/// crate.
32
45
#[ inline]
33
46
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 ( ) )
36
48
}
37
49
38
50
/// Creates a forest containing a `DefId` and all its descendants.
39
51
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
+ }
43
70
}
44
71
45
72
/// Tests whether the forest is empty.
46
73
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 ( )
48
83
}
49
84
50
85
/// Tests whether the forest contains a given DefId.
51
86
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 )
53
88
}
54
89
55
90
/// Calculate the intersection of a collection of forests.
@@ -58,56 +93,55 @@ impl<'tcx> DefIdForest {
58
93
I : IntoIterator < Item = DefIdForest > ,
59
94
{
60
95
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 ( ) )
63
98
} else {
64
99
return DefIdForest :: full ( tcx) ;
65
100
} ;
66
101
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 ( ) ;
69
103
for next_forest in iter {
70
104
// 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 ( ) ;
73
107
}
74
108
75
- for id in ret. root_ids . drain ( ..) {
76
- if next_forest. contains ( tcx, id) {
77
- next_ret. push ( id) ;
78
- } else {
79
- old_ret. push ( id) ;
80
- }
81
- }
82
- ret. root_ids . extend ( old_ret. drain ( ..) ) ;
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) ) ) ;
111
+ // We keep the elements in `next_forest` that are also in `ret`.
112
+ next_ret. extend ( next_forest. iter ( ) . filter ( |& id| slice_contains ( tcx, & ret, id) ) ) ;
83
113
84
- next_ret. extend ( next_forest. root_ids . into_iter ( ) . filter ( |& id| ret. contains ( tcx, id) ) ) ;
85
-
86
- mem:: swap ( & mut next_ret, & mut ret. root_ids ) ;
87
- next_ret. drain ( ..) ;
114
+ mem:: swap ( & mut next_ret, & mut ret) ;
115
+ next_ret. clear ( ) ;
88
116
}
89
- ret
117
+ DefIdForest :: from_slice ( & ret)
90
118
}
91
119
92
120
/// Calculate the union of a collection of forests.
93
121
pub fn union < I > ( tcx : TyCtxt < ' tcx > , iter : I ) -> DefIdForest
94
122
where
95
123
I : IntoIterator < Item = DefIdForest > ,
96
124
{
97
- let mut ret = DefIdForest :: empty ( ) ;
98
- let mut next_ret = SmallVec :: new ( ) ;
125
+ let mut ret: SmallVec < [ _ ; 1 ] > = SmallVec :: new ( ) ;
126
+ let mut next_ret: SmallVec < [ _ ; 1 ] > = SmallVec :: new ( ) ;
99
127
for next_forest in iter {
100
- 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
+ }
101
132
102
- for id in next_forest. root_ids {
103
- 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) {
104
138
next_ret. push ( id) ;
105
139
}
106
140
}
107
141
108
- mem:: swap ( & mut next_ret, & mut ret. root_ids ) ;
109
- next_ret. drain ( .. ) ;
142
+ mem:: swap ( & mut next_ret, & mut ret) ;
143
+ next_ret. clear ( ) ;
110
144
}
111
- ret
145
+ DefIdForest :: from_slice ( & ret)
112
146
}
113
147
}
0 commit comments