1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::ty::context::TyCtxt;
use crate::ty::{DefId, DefIdTree};
use rustc_hir::CRATE_HIR_ID;
use smallvec::SmallVec;
use std::mem;
#[derive(Clone)]
pub struct DefIdForest {
root_ids: SmallVec<[DefId; 1]>,
}
impl<'tcx> DefIdForest {
pub fn empty() -> DefIdForest {
DefIdForest { root_ids: SmallVec::new() }
}
#[inline]
pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest {
let crate_id = tcx.hir().local_def_id(CRATE_HIR_ID);
DefIdForest::from_id(crate_id.to_def_id())
}
pub fn from_id(id: DefId) -> DefIdForest {
let mut root_ids = SmallVec::new();
root_ids.push(id);
DefIdForest { root_ids }
}
pub fn is_empty(&self) -> bool {
self.root_ids.is_empty()
}
pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
self.root_ids.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
}
pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
where
I: IntoIterator<Item = DefIdForest>,
{
let mut iter = iter.into_iter();
let mut ret = if let Some(first) = iter.next() {
first
} else {
return DefIdForest::full(tcx);
};
let mut next_ret = SmallVec::new();
let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new();
for next_forest in iter {
if ret.is_empty() {
break;
}
for id in ret.root_ids.drain(..) {
if next_forest.contains(tcx, id) {
next_ret.push(id);
} else {
old_ret.push(id);
}
}
ret.root_ids.extend(old_ret.drain(..));
next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id)));
mem::swap(&mut next_ret, &mut ret.root_ids);
next_ret.drain(..);
}
ret
}
pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
where
I: IntoIterator<Item = DefIdForest>,
{
let mut ret = DefIdForest::empty();
let mut next_ret = SmallVec::new();
for next_forest in iter {
next_ret.extend(ret.root_ids.drain(..).filter(|&id| !next_forest.contains(tcx, id)));
for id in next_forest.root_ids {
if !next_ret.contains(&id) {
next_ret.push(id);
}
}
mem::swap(&mut next_ret, &mut ret.root_ids);
next_ret.drain(..);
}
ret
}
}