Skip to content

Commit 5d9dd7c

Browse files
committed
Refactor overlap checker so that it walks the HIR instead of poking into
random tables. The old code was weird anyway because it would potentially walk traits from other crates etc. The new code fits seamlessly with the dependency tracking.
1 parent 75c4f39 commit 5d9dd7c

File tree

1 file changed

+35
-26
lines changed

1 file changed

+35
-26
lines changed

src/librustc_typeck/coherence/overlap.rs

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,53 +18,53 @@ use middle::ty;
1818
use middle::infer;
1919
use syntax::ast;
2020
use syntax::codemap::Span;
21+
use rustc::dep_graph::DepNode;
2122
use rustc_front::hir;
2223
use rustc_front::intravisit;
23-
use util::nodemap::DefIdMap;
24+
use util::nodemap::{DefIdMap, DefIdSet};
2425

2526
pub fn check(tcx: &ty::ctxt) {
26-
let mut overlap = OverlapChecker { tcx: tcx, default_impls: DefIdMap() };
27-
overlap.check_for_overlapping_impls();
27+
let mut overlap = OverlapChecker { tcx: tcx,
28+
traits_checked: DefIdSet(),
29+
default_impls: DefIdMap() };
2830

2931
// this secondary walk specifically checks for some other cases,
3032
// like defaulted traits, for which additional overlap rules exist
31-
tcx.map.krate().visit_all_items(&mut overlap);
33+
tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
3234
}
3335

3436
struct OverlapChecker<'cx, 'tcx:'cx> {
3537
tcx: &'cx ty::ctxt<'tcx>,
3638

39+
// The set of traits where we have checked for overlap. This is
40+
// used to avoid checking the same trait twice.
41+
//
42+
// NB. It's ok to skip tracking this set because we fully
43+
// encapsulate it, and we always create a task
44+
// (`CoherenceOverlapCheck`) corresponding to each entry.
45+
traits_checked: DefIdSet,
46+
3747
// maps from a trait def-id to an impl id
3848
default_impls: DefIdMap<ast::NodeId>,
3949
}
4050

4151
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
42-
fn check_for_overlapping_impls(&self) {
43-
debug!("check_for_overlapping_impls");
44-
45-
// Collect this into a vector to avoid holding the
46-
// refcell-lock during the
47-
// check_for_overlapping_impls_of_trait() check, since that
48-
// check can populate this table further with impls from other
49-
// crates.
50-
let trait_defs: Vec<_> = self.tcx.trait_defs.borrow().values().cloned().collect();
51-
52-
for trait_def in trait_defs {
53-
self.tcx.populate_implementations_for_trait_if_necessary(trait_def.trait_ref.def_id);
54-
self.check_for_overlapping_impls_of_trait(trait_def);
52+
fn check_for_overlapping_impls_of_trait(&mut self, trait_def_id: DefId) {
53+
debug!("check_for_overlapping_impls_of_trait(trait_def_id={:?})",
54+
trait_def_id);
55+
56+
let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
57+
if !self.traits_checked.insert(trait_def_id) {
58+
return;
5559
}
56-
}
5760

58-
fn check_for_overlapping_impls_of_trait(&self,
59-
trait_def: &'tcx ty::TraitDef<'tcx>)
60-
{
61-
debug!("check_for_overlapping_impls_of_trait(trait_def={:?})",
62-
trait_def);
61+
let trait_def = self.tcx.lookup_trait_def(trait_def_id);
62+
self.tcx.populate_implementations_for_trait_if_necessary(
63+
trait_def.trait_ref.def_id);
6364

6465
// We should already know all impls of this trait, so these
6566
// borrows are safe.
66-
let blanket_impls = trait_def.blanket_impls.borrow();
67-
let nonblanket_impls = trait_def.nonblanket_impls.borrow();
67+
let (blanket_impls, nonblanket_impls) = trait_def.borrow_impl_lists(self.tcx);
6868

6969
// Conflicts can only occur between a blanket impl and another impl,
7070
// or between 2 non-blanket impls of the same kind.
@@ -175,12 +175,20 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
175175
impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
176176
fn visit_item(&mut self, item: &'v hir::Item) {
177177
match item.node {
178-
hir::ItemDefaultImpl(_, _) => {
178+
hir::ItemTrait(..) => {
179+
let trait_def_id = self.tcx.map.local_def_id(item.id);
180+
self.check_for_overlapping_impls_of_trait(trait_def_id);
181+
}
182+
183+
hir::ItemDefaultImpl(..) => {
179184
// look for another default impl; note that due to the
180185
// general orphan/coherence rules, it must always be
181186
// in this crate.
182187
let impl_def_id = self.tcx.map.local_def_id(item.id);
183188
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
189+
190+
self.check_for_overlapping_impls_of_trait(trait_ref.def_id);
191+
184192
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
185193
match prev_default_impl {
186194
Some(prev_id) => {
@@ -195,6 +203,7 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
195203
let impl_def_id = self.tcx.map.local_def_id(item.id);
196204
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
197205
let trait_def_id = trait_ref.def_id;
206+
self.check_for_overlapping_impls_of_trait(trait_def_id);
198207
match trait_ref.self_ty().sty {
199208
ty::TyTrait(ref data) => {
200209
// This is something like impl Trait1 for Trait2. Illegal

0 commit comments

Comments
 (0)