Skip to content

Commit 742ebc1

Browse files
Share lists of blanket impls in results of relevant_impls_for() query.
1 parent 40a6734 commit 742ebc1

File tree

3 files changed

+108
-27
lines changed

3 files changed

+108
-27
lines changed

src/librustc/traits/specialize/mod.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,19 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
293293
-> Rc<specialization_graph::Graph> {
294294
let mut sg = specialization_graph::Graph::new();
295295

296-
for &impl_def_id in tcx.trait_impls_of(trait_id).iter() {
296+
let mut trait_impls: Vec<DefId> = tcx.trait_impls_of(trait_id).iter().collect();
297+
298+
// The coherence checking implementation seems to rely on impls being
299+
// iterated over (roughly) in definition order, so we are sorting by
300+
// negated CrateNum (so remote definitions are visited first) and then
301+
// by a flattend version of the DefIndex.
302+
trait_impls.sort_unstable_by_key(|def_id| {
303+
(-(def_id.krate.as_u32() as i64),
304+
def_id.index.address_space().index(),
305+
def_id.index.as_array_index())
306+
});
307+
308+
for impl_def_id in trait_impls {
297309
if impl_def_id.is_local() {
298310
// This is where impl overlap checking happens:
299311
let insert_result = sg.insert(tcx, impl_def_id);

src/librustc/ty/maps.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -850,10 +850,10 @@ define_maps! { <'tcx>
850850
[] const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
851851
[] is_mir_available: IsMirAvailable(DefId) -> bool,
852852

853-
[] trait_impls_of: TraitImpls(DefId) -> Rc<Vec<DefId>>,
853+
[] trait_impls_of: TraitImpls(DefId) -> ty::trait_def::TraitImpls,
854854
// Note that TraitDef::for_each_relevant_impl() will do type simplication for you.
855855
[] relevant_trait_impls_for: relevant_trait_impls_for((DefId, SimplifiedType))
856-
-> Rc<Vec<DefId>>,
856+
-> ty::trait_def::TraitImpls,
857857
[] specialization_graph_of: SpecializationGraph(DefId) -> Rc<specialization_graph::Graph>,
858858
[] is_object_safe: ObjectSafety(DefId) -> bool,
859859
}

src/librustc/ty/trait_def.rs

+93-24
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,60 @@ pub struct TraitDef {
3535
pub def_path_hash: u64,
3636
}
3737

38+
// We don't store the list of impls in a flat list because each cached list of
39+
// `relevant_impls_for` we would then duplicate all blanket impls. By keeping
40+
// blanket and non-blanket impls separate, we can share the list of blanket
41+
// impls.
42+
#[derive(Clone)]
43+
pub struct TraitImpls {
44+
blanket_impls: Rc<Vec<DefId>>,
45+
non_blanket_impls: Rc<Vec<DefId>>,
46+
}
47+
48+
impl TraitImpls {
49+
pub fn iter(&self) -> TraitImplsIter {
50+
TraitImplsIter {
51+
blanket_impls: self.blanket_impls.clone(),
52+
non_blanket_impls: self.non_blanket_impls.clone(),
53+
index: 0
54+
}
55+
}
56+
}
57+
58+
#[derive(Clone)]
59+
pub struct TraitImplsIter {
60+
blanket_impls: Rc<Vec<DefId>>,
61+
non_blanket_impls: Rc<Vec<DefId>>,
62+
index: usize,
63+
}
64+
65+
impl Iterator for TraitImplsIter {
66+
type Item = DefId;
67+
68+
fn next(&mut self) -> Option<DefId> {
69+
if self.index < self.blanket_impls.len() {
70+
let bi_index = self.index;
71+
self.index += 1;
72+
Some(self.blanket_impls[bi_index])
73+
} else {
74+
let nbi_index = self.index - self.blanket_impls.len();
75+
if nbi_index < self.non_blanket_impls.len() {
76+
self.index += 1;
77+
Some(self.non_blanket_impls[nbi_index])
78+
} else {
79+
None
80+
}
81+
}
82+
}
83+
84+
fn size_hint(&self) -> (usize, Option<usize>) {
85+
let items_left = (self.blanket_impls.len() + self.non_blanket_impls.len()) - self.index;
86+
(items_left, Some(items_left))
87+
}
88+
}
89+
90+
impl ExactSizeIterator for TraitImplsIter {}
91+
3892
impl<'a, 'gcx, 'tcx> TraitDef {
3993
pub fn new(def_id: DefId,
4094
unsafety: hir::Unsafety,
@@ -58,7 +112,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
58112
}
59113

60114
pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
61-
for &impl_def_id in tcx.trait_impls_of(self.def_id).iter() {
115+
for impl_def_id in tcx.trait_impls_of(self.def_id).iter() {
62116
f(impl_def_id);
63117
}
64118
}
@@ -89,7 +143,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
89143
tcx.trait_impls_of(self.def_id)
90144
};
91145

92-
for &impl_def_id in relevant_impls.iter() {
146+
for impl_def_id in relevant_impls.iter() {
93147
f(impl_def_id);
94148
}
95149
}
@@ -98,55 +152,70 @@ impl<'a, 'gcx, 'tcx> TraitDef {
98152
// Query provider for `trait_impls_of`.
99153
pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
100154
trait_id: DefId)
101-
-> Rc<Vec<DefId>> {
102-
let mut impls = if trait_id.is_local() {
155+
-> TraitImpls {
156+
let remote_impls = if trait_id.is_local() {
103157
// Traits defined in the current crate can't have impls in upstream
104158
// crates, so we don't bother querying the cstore.
105159
Vec::new()
106160
} else {
107161
tcx.sess.cstore.implementations_of_trait(Some(trait_id))
108162
};
109163

110-
impls.extend(tcx.hir
111-
.trait_impls(trait_id)
112-
.iter()
113-
.map(|&node_id| tcx.hir.local_def_id(node_id))
114-
.filter(|&impl_def_id| {
115-
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
116-
!trait_ref.references_error()
117-
}));
118-
Rc::new(impls)
164+
let mut blanket_impls = Vec::new();
165+
let mut non_blanket_impls = Vec::new();
166+
167+
let local_impls = tcx.hir
168+
.trait_impls(trait_id)
169+
.into_iter()
170+
.map(|&node_id| tcx.hir.local_def_id(node_id));
171+
172+
for impl_def_id in local_impls.chain(remote_impls.into_iter()) {
173+
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
174+
if impl_def_id.is_local() && impl_trait_ref.references_error() {
175+
continue
176+
}
177+
178+
if fast_reject::simplify_type(tcx, impl_trait_ref.self_ty(), false).is_some() {
179+
non_blanket_impls.push(impl_def_id);
180+
} else {
181+
blanket_impls.push(impl_def_id);
182+
}
183+
}
184+
185+
TraitImpls {
186+
blanket_impls: Rc::new(blanket_impls),
187+
non_blanket_impls: Rc::new(non_blanket_impls),
188+
}
119189
}
120190

121191
// Query provider for `relevant_trait_impls_for`.
122192
pub(super) fn relevant_trait_impls_provider<'a, 'tcx>(
123193
tcx: TyCtxt<'a, 'tcx, 'tcx>,
124194
(trait_id, self_ty): (DefId, fast_reject::SimplifiedType))
125-
-> Rc<Vec<DefId>>
195+
-> TraitImpls
126196
{
127197
let all_trait_impls = tcx.trait_impls_of(trait_id);
128198

129199
let relevant: Vec<DefId> = all_trait_impls
200+
.non_blanket_impls
130201
.iter()
131-
.map(|&impl_def_id| impl_def_id)
202+
.cloned()
132203
.filter(|&impl_def_id| {
133204
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
134205
let impl_simple_self_ty = fast_reject::simplify_type(tcx,
135206
impl_trait_ref.self_ty(),
136-
false);
137-
if let Some(impl_simple_self_ty) = impl_simple_self_ty {
138-
impl_simple_self_ty == self_ty
139-
} else {
140-
// blanket impl (?)
141-
true
142-
}
207+
false).unwrap();
208+
impl_simple_self_ty == self_ty
143209
})
144210
.collect();
145211

146-
if all_trait_impls.len() == relevant.len() {
212+
if all_trait_impls.non_blanket_impls.len() == relevant.len() {
147213
// If we didn't filter anything out, re-use the existing vec.
148214
all_trait_impls
149215
} else {
150-
Rc::new(relevant)
216+
TraitImpls {
217+
blanket_impls: all_trait_impls.blanket_impls.clone(),
218+
non_blanket_impls: Rc::new(relevant),
219+
}
151220
}
152221
}

0 commit comments

Comments
 (0)