Skip to content

Commit 2fc1586

Browse files
committed
go back to the older model of coherence collect
1 parent 4b5613c commit 2fc1586

File tree

2 files changed

+43
-19
lines changed

2 files changed

+43
-19
lines changed

src/librustc/dep_graph/dep_tracking_map.rs

+15
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,21 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
7575
pub fn keys(&self) -> Vec<M::Key> {
7676
self.map.keys().cloned().collect()
7777
}
78+
79+
/// Append `elem` to the vector stored for `k`, creating a new vector if needed.
80+
/// This is considered a write to `k`.
81+
///
82+
/// NOTE: Caution is required when using this method. You should
83+
/// be sure that nobody is **reading from the vector** while you
84+
/// are writing to it. Eventually, it'd be nice to remove this.
85+
pub fn push<E: Clone>(&mut self, k: M::Key, elem: E)
86+
where M: DepTrackingMapConfig<Value=Vec<E>>
87+
{
88+
self.write(&k);
89+
self.map.entry(k)
90+
.or_insert(Vec::new())
91+
.push(elem);
92+
}
7893
}
7994

8095
impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {

src/librustc_typeck/coherence/mod.rs

+28-19
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
// done by the orphan and overlap modules. Then we build up various
1616
// mappings. That mapping code resides here.
1717

18+
use dep_graph::DepTrackingMap;
1819
use hir::def_id::DefId;
19-
use rustc::ty::{self, TyCtxt, TypeFoldable};
20+
use rustc::ty::{self, maps, TyCtxt, TypeFoldable};
2021
use rustc::ty::{Ty, TyBool, TyChar, TyError};
2122
use rustc::ty::{TyParam, TyRawPtr};
2223
use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
@@ -29,7 +30,7 @@ use rustc::dep_graph::DepNode;
2930
use rustc::hir::itemlikevisit::ItemLikeVisitor;
3031
use rustc::hir::{Item, ItemImpl};
3132
use rustc::hir;
32-
use rustc::util::nodemap::DefIdMap;
33+
use std::cell::RefMut;
3334

3435
mod builtin;
3536
mod orphan;
@@ -38,7 +39,7 @@ mod unsafety;
3839

3940
struct CoherenceCollect<'a, 'tcx: 'a> {
4041
tcx: TyCtxt<'a, 'tcx, 'tcx>,
41-
inherent_impls: DefIdMap<Vec<DefId>>,
42+
inherent_impls: RefMut<'a, DepTrackingMap<maps::InherentImpls<'tcx>>>,
4243
}
4344

4445
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCollect<'a, 'tcx> {
@@ -56,6 +57,16 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCollect<'a, 'tcx> {
5657
}
5758

5859
impl<'a, 'tcx> CoherenceCollect<'a, 'tcx> {
60+
fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
61+
let inherent_impls = tcx.inherent_impls.borrow_mut();
62+
let mut this = &mut CoherenceCollect { tcx, inherent_impls };
63+
64+
// Check implementations and traits. This populates the tables
65+
// containing the inherent methods and extension methods. It also
66+
// builds up the trait inheritance table.
67+
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, this);
68+
}
69+
5970
// Returns the def ID of the base type, if there is one.
6071
fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
6172
match ty.sty {
@@ -77,18 +88,6 @@ impl<'a, 'tcx> CoherenceCollect<'a, 'tcx> {
7788
}
7889
}
7990

80-
fn check(&mut self) {
81-
// Check implementations and traits. This populates the tables
82-
// containing the inherent methods and extension methods. It also
83-
// builds up the trait inheritance table.
84-
self.tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, self);
85-
86-
// Transfer the inherent impl lists, not that they are known, into the tcx
87-
for (ty_def_id, impl_def_ids) in self.inherent_impls.drain() {
88-
self.tcx.inherent_impls.borrow_mut().insert(ty_def_id, impl_def_ids);
89-
}
90-
}
91-
9291
fn check_implementation(&mut self, item: &Item) {
9392
let tcx = self.tcx;
9493
let impl_did = tcx.hir.local_def_id(item.id);
@@ -127,9 +126,18 @@ impl<'a, 'tcx> CoherenceCollect<'a, 'tcx> {
127126
}
128127

129128
fn add_inherent_impl(&mut self, base_def_id: DefId, impl_def_id: DefId) {
130-
self.inherent_impls.entry(base_def_id)
131-
.or_insert(vec![])
132-
.push(impl_def_id);
129+
// Subtle: it'd be better to collect these into a local map
130+
// and then write the vector only once all items are known,
131+
// but that leads to degenerate dep-graphs. The problem is
132+
// that the write of that big vector winds up having reads
133+
// from *all* impls in the krate, since we've lost the
134+
// precision basically. This would be ok in the firewall
135+
// model so once we've made progess towards that we can modify
136+
// the strategy here. In the meantime, using `push` is ok
137+
// because we are doing this as a pre-pass before anyone
138+
// actually reads from `inherent_impls` -- and we know this is
139+
// true beacuse we hold the refcell lock.
140+
self.inherent_impls.push(base_def_id, impl_def_id);
133141
}
134142

135143
fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
@@ -169,8 +177,9 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
169177
}
170178

171179
pub fn check_coherence(ccx: &CrateCtxt) {
180+
CoherenceCollect::check(ccx.tcx);
181+
172182
let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
173-
CoherenceCollect { tcx: ccx.tcx, inherent_impls: DefIdMap() }.check();
174183
unsafety::check(ccx.tcx);
175184
orphan::check(ccx.tcx);
176185
overlap::check(ccx.tcx);

0 commit comments

Comments
 (0)