Skip to content

Commit

Permalink
Share lists of blanket impls in results of relevant_impls_for() query.
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelwoerister committed May 15, 2017
1 parent 40a6734 commit 742ebc1
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 27 deletions.
14 changes: 13 additions & 1 deletion src/librustc/traits/specialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,19 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
-> Rc<specialization_graph::Graph> {
let mut sg = specialization_graph::Graph::new();

for &impl_def_id in tcx.trait_impls_of(trait_id).iter() {
let mut trait_impls: Vec<DefId> = tcx.trait_impls_of(trait_id).iter().collect();

// The coherence checking implementation seems to rely on impls being
// iterated over (roughly) in definition order, so we are sorting by
// negated CrateNum (so remote definitions are visited first) and then
// by a flattend version of the DefIndex.
trait_impls.sort_unstable_by_key(|def_id| {
(-(def_id.krate.as_u32() as i64),
def_id.index.address_space().index(),
def_id.index.as_array_index())
});

for impl_def_id in trait_impls {
if impl_def_id.is_local() {
// This is where impl overlap checking happens:
let insert_result = sg.insert(tcx, impl_def_id);
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/maps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -850,10 +850,10 @@ define_maps! { <'tcx>
[] const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
[] is_mir_available: IsMirAvailable(DefId) -> bool,

[] trait_impls_of: TraitImpls(DefId) -> Rc<Vec<DefId>>,
[] trait_impls_of: TraitImpls(DefId) -> ty::trait_def::TraitImpls,
// Note that TraitDef::for_each_relevant_impl() will do type simplication for you.
[] relevant_trait_impls_for: relevant_trait_impls_for((DefId, SimplifiedType))
-> Rc<Vec<DefId>>,
-> ty::trait_def::TraitImpls,
[] specialization_graph_of: SpecializationGraph(DefId) -> Rc<specialization_graph::Graph>,
[] is_object_safe: ObjectSafety(DefId) -> bool,
}
Expand Down
117 changes: 93 additions & 24 deletions src/librustc/ty/trait_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,60 @@ pub struct TraitDef {
pub def_path_hash: u64,
}

// We don't store the list of impls in a flat list because each cached list of
// `relevant_impls_for` we would then duplicate all blanket impls. By keeping
// blanket and non-blanket impls separate, we can share the list of blanket
// impls.
#[derive(Clone)]
pub struct TraitImpls {
blanket_impls: Rc<Vec<DefId>>,
non_blanket_impls: Rc<Vec<DefId>>,
}

impl TraitImpls {
pub fn iter(&self) -> TraitImplsIter {
TraitImplsIter {
blanket_impls: self.blanket_impls.clone(),
non_blanket_impls: self.non_blanket_impls.clone(),
index: 0
}
}
}

#[derive(Clone)]
pub struct TraitImplsIter {
blanket_impls: Rc<Vec<DefId>>,
non_blanket_impls: Rc<Vec<DefId>>,
index: usize,
}

impl Iterator for TraitImplsIter {
type Item = DefId;

fn next(&mut self) -> Option<DefId> {
if self.index < self.blanket_impls.len() {
let bi_index = self.index;
self.index += 1;
Some(self.blanket_impls[bi_index])
} else {
let nbi_index = self.index - self.blanket_impls.len();
if nbi_index < self.non_blanket_impls.len() {
self.index += 1;
Some(self.non_blanket_impls[nbi_index])
} else {
None
}
}
}

fn size_hint(&self) -> (usize, Option<usize>) {
let items_left = (self.blanket_impls.len() + self.non_blanket_impls.len()) - self.index;
(items_left, Some(items_left))
}
}

impl ExactSizeIterator for TraitImplsIter {}

impl<'a, 'gcx, 'tcx> TraitDef {
pub fn new(def_id: DefId,
unsafety: hir::Unsafety,
Expand All @@ -58,7 +112,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
}

pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
for &impl_def_id in tcx.trait_impls_of(self.def_id).iter() {
for impl_def_id in tcx.trait_impls_of(self.def_id).iter() {
f(impl_def_id);
}
}
Expand Down Expand Up @@ -89,7 +143,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
tcx.trait_impls_of(self.def_id)
};

for &impl_def_id in relevant_impls.iter() {
for impl_def_id in relevant_impls.iter() {
f(impl_def_id);
}
}
Expand All @@ -98,55 +152,70 @@ impl<'a, 'gcx, 'tcx> TraitDef {
// Query provider for `trait_impls_of`.
pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_id: DefId)
-> Rc<Vec<DefId>> {
let mut impls = if trait_id.is_local() {
-> TraitImpls {
let remote_impls = if trait_id.is_local() {
// Traits defined in the current crate can't have impls in upstream
// crates, so we don't bother querying the cstore.
Vec::new()
} else {
tcx.sess.cstore.implementations_of_trait(Some(trait_id))
};

impls.extend(tcx.hir
.trait_impls(trait_id)
.iter()
.map(|&node_id| tcx.hir.local_def_id(node_id))
.filter(|&impl_def_id| {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
!trait_ref.references_error()
}));
Rc::new(impls)
let mut blanket_impls = Vec::new();
let mut non_blanket_impls = Vec::new();

let local_impls = tcx.hir
.trait_impls(trait_id)
.into_iter()
.map(|&node_id| tcx.hir.local_def_id(node_id));

for impl_def_id in local_impls.chain(remote_impls.into_iter()) {
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
if impl_def_id.is_local() && impl_trait_ref.references_error() {
continue
}

if fast_reject::simplify_type(tcx, impl_trait_ref.self_ty(), false).is_some() {
non_blanket_impls.push(impl_def_id);
} else {
blanket_impls.push(impl_def_id);
}
}

TraitImpls {
blanket_impls: Rc::new(blanket_impls),
non_blanket_impls: Rc::new(non_blanket_impls),
}
}

// Query provider for `relevant_trait_impls_for`.
pub(super) fn relevant_trait_impls_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
(trait_id, self_ty): (DefId, fast_reject::SimplifiedType))
-> Rc<Vec<DefId>>
-> TraitImpls
{
let all_trait_impls = tcx.trait_impls_of(trait_id);

let relevant: Vec<DefId> = all_trait_impls
.non_blanket_impls
.iter()
.map(|&impl_def_id| impl_def_id)
.cloned()
.filter(|&impl_def_id| {
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let impl_simple_self_ty = fast_reject::simplify_type(tcx,
impl_trait_ref.self_ty(),
false);
if let Some(impl_simple_self_ty) = impl_simple_self_ty {
impl_simple_self_ty == self_ty
} else {
// blanket impl (?)
true
}
false).unwrap();
impl_simple_self_ty == self_ty
})
.collect();

if all_trait_impls.len() == relevant.len() {
if all_trait_impls.non_blanket_impls.len() == relevant.len() {
// If we didn't filter anything out, re-use the existing vec.
all_trait_impls
} else {
Rc::new(relevant)
TraitImpls {
blanket_impls: all_trait_impls.blanket_impls.clone(),
non_blanket_impls: Rc::new(relevant),
}
}
}

0 comments on commit 742ebc1

Please sign in to comment.