Skip to content

Commit 4640e18

Browse files
committed
Auto merge of #41911 - michaelwoerister:querify_trait_def, r=nikomatsakis
Remove interior mutability from TraitDef by turning fields into queries This PR gets rid of anything `std::cell` in `TraitDef` by - moving the global list of trait impls from `TraitDef` into a query, - moving the list of trait impls relevent for some self-type from `TraitDef` into a query - moving the specialization graph of trait impls into a query, and - moving `TraitDef::object_safety` into a query. I really like how querifying things not only helps with incremental compilation and on-demand, but also just plain makes the code cleaner `:)` There are also some smaller fixes in the PR. Commits can be reviewed separately. r? @eddyb or @nikomatsakis
2 parents 7b5c3d2 + 08660af commit 4640e18

File tree

32 files changed

+678
-587
lines changed

32 files changed

+678
-587
lines changed

src/librustc/dep_graph/dep_node.rs

+7
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ pub enum DepNode<D: Clone + Debug> {
106106
UsedTraitImports(D),
107107
ConstEval(D),
108108
SymbolName(D),
109+
SpecializationGraph(D),
110+
ObjectSafety(D),
109111

110112
// The set of impls for a given trait. Ultimately, it would be
111113
// nice to get more fine-grained here (e.g., to include a
@@ -116,6 +118,8 @@ pub enum DepNode<D: Clone + Debug> {
116118
// than changes in the impl body.
117119
TraitImpls(D),
118120

121+
AllLocalTraitImpls,
122+
119123
// Nodes representing caches. To properly handle a true cache, we
120124
// don't use a DepTrackingMap, but rather we push a task node.
121125
// Otherwise the write into the map would be incorrectly
@@ -262,7 +266,10 @@ impl<D: Clone + Debug> DepNode<D> {
262266
UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
263267
ConstEval(ref d) => op(d).map(ConstEval),
264268
SymbolName(ref d) => op(d).map(SymbolName),
269+
SpecializationGraph(ref d) => op(d).map(SpecializationGraph),
270+
ObjectSafety(ref d) => op(d).map(ObjectSafety),
265271
TraitImpls(ref d) => op(d).map(TraitImpls),
272+
AllLocalTraitImpls => Some(AllLocalTraitImpls),
266273
TraitItems(ref d) => op(d).map(TraitItems),
267274
ReprHints(ref d) => op(d).map(ReprHints),
268275
TraitSelect { ref trait_def_id, ref input_def_id } => {

src/librustc/diagnostics.rs

+61
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,67 @@ RFC. It is, however, [currently unimplemented][iss15872].
409409
[iss15872]: https://github.com/rust-lang/rust/issues/15872
410410
"##,
411411

412+
E0119: r##"
413+
There are conflicting trait implementations for the same type.
414+
Example of erroneous code:
415+
416+
```compile_fail,E0119
417+
trait MyTrait {
418+
fn get(&self) -> usize;
419+
}
420+
421+
impl<T> MyTrait for T {
422+
fn get(&self) -> usize { 0 }
423+
}
424+
425+
struct Foo {
426+
value: usize
427+
}
428+
429+
impl MyTrait for Foo { // error: conflicting implementations of trait
430+
// `MyTrait` for type `Foo`
431+
fn get(&self) -> usize { self.value }
432+
}
433+
```
434+
435+
When looking for the implementation for the trait, the compiler finds
436+
both the `impl<T> MyTrait for T` where T is all types and the `impl
437+
MyTrait for Foo`. Since a trait cannot be implemented multiple times,
438+
this is an error. So, when you write:
439+
440+
```
441+
trait MyTrait {
442+
fn get(&self) -> usize;
443+
}
444+
445+
impl<T> MyTrait for T {
446+
fn get(&self) -> usize { 0 }
447+
}
448+
```
449+
450+
This makes the trait implemented on all types in the scope. So if you
451+
try to implement it on another one after that, the implementations will
452+
conflict. Example:
453+
454+
```
455+
trait MyTrait {
456+
fn get(&self) -> usize;
457+
}
458+
459+
impl<T> MyTrait for T {
460+
fn get(&self) -> usize { 0 }
461+
}
462+
463+
struct Foo;
464+
465+
fn main() {
466+
let f = Foo;
467+
468+
f.get(); // the trait is implemented so we can use it
469+
}
470+
```
471+
"##,
472+
412473
E0133: r##"
413474
Unsafe code was used outside of an unsafe function or block.
414475

src/librustc/hir/map/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -497,15 +497,15 @@ impl<'hir> Map<'hir> {
497497
}
498498

499499
pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] {
500-
self.dep_graph.read(DepNode::TraitImpls(trait_did));
500+
self.dep_graph.read(DepNode::AllLocalTraitImpls);
501501

502502
// NB: intentionally bypass `self.forest.krate()` so that we
503503
// do not trigger a read of the whole krate here
504504
self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..])
505505
}
506506

507507
pub fn trait_default_impl(&self, trait_did: DefId) -> Option<NodeId> {
508-
self.dep_graph.read(DepNode::TraitImpls(trait_did));
508+
self.dep_graph.read(DepNode::AllLocalTraitImpls);
509509

510510
// NB: intentionally bypass `self.forest.krate()` so that we
511511
// do not trigger a read of the whole krate here

src/librustc/ich/fingerprint.rs

+8
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,11 @@ impl stable_hasher::StableHasherResult for Fingerprint {
9494
fingerprint
9595
}
9696
}
97+
98+
impl<CTX> stable_hasher::HashStable<CTX> for Fingerprint {
99+
fn hash_stable<W: stable_hasher::StableHasherResult>(&self,
100+
_: &mut CTX,
101+
hasher: &mut stable_hasher::StableHasher<W>) {
102+
::std::hash::Hash::hash(&self.0, hasher);
103+
}
104+
}

src/librustc/ich/hcx.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use ty;
1616
use util::nodemap::NodeMap;
1717

1818
use std::hash as std_hash;
19-
use std::collections::{HashMap, HashSet};
19+
use std::collections::{HashMap, HashSet, BTreeMap};
2020

2121
use syntax::ast;
2222
use syntax::attr;
@@ -348,3 +348,25 @@ pub fn hash_stable_nodemap<'a, 'tcx, V, W>(hcx: &mut StableHashingContext<'a, 't
348348
hcx.tcx.hir.definitions().node_to_hir_id(*node_id).local_id
349349
});
350350
}
351+
352+
353+
pub fn hash_stable_btreemap<'a, 'tcx, K, V, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>,
354+
hasher: &mut StableHasher<W>,
355+
map: &BTreeMap<K, V>,
356+
extract_stable_key: F)
357+
where K: Eq + Ord,
358+
V: HashStable<StableHashingContext<'a, 'tcx>>,
359+
SK: HashStable<StableHashingContext<'a, 'tcx>> + Ord + Clone,
360+
F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK,
361+
W: StableHasherResult,
362+
{
363+
let mut keys: Vec<_> = map.keys()
364+
.map(|k| (extract_stable_key(hcx, k), k))
365+
.collect();
366+
keys.sort_unstable_by_key(|&(ref stable_key, _)| stable_key.clone());
367+
keys.len().hash_stable(hcx, hasher);
368+
for (stable_key, key) in keys {
369+
stable_key.hash_stable(hcx, hasher);
370+
map[key].hash_stable(hcx, hasher);
371+
}
372+
}

src/librustc/ich/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
pub use self::fingerprint::Fingerprint;
1414
pub use self::caching_codemap_view::CachingCodemapView;
1515
pub use self::hcx::{StableHashingContext, NodeIdHashingMode, hash_stable_hashmap,
16-
hash_stable_hashset, hash_stable_nodemap};
16+
hash_stable_hashset, hash_stable_nodemap,
17+
hash_stable_btreemap};
1718
mod fingerprint;
1819
mod caching_codemap_view;
1920
mod hcx;

src/librustc/traits/mod.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -619,8 +619,6 @@ pub fn get_vtable_methods<'a, 'tcx>(
619619
debug!("get_vtable_methods({:?})", trait_ref);
620620

621621
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
622-
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
623-
624622
let trait_methods = tcx.associated_items(trait_ref.def_id())
625623
.filter(|item| item.kind == ty::AssociatedKind::Method);
626624

@@ -782,3 +780,19 @@ impl<'tcx> TraitObligation<'tcx> {
782780
ty::Binder(self.predicate.skip_binder().self_ty())
783781
}
784782
}
783+
784+
pub fn provide(providers: &mut ty::maps::Providers) {
785+
*providers = ty::maps::Providers {
786+
is_object_safe: object_safety::is_object_safe_provider,
787+
specialization_graph_of: specialize::specialization_graph_provider,
788+
..*providers
789+
};
790+
}
791+
792+
pub fn provide_extern(providers: &mut ty::maps::Providers) {
793+
*providers = ty::maps::Providers {
794+
is_object_safe: object_safety::is_object_safe_provider,
795+
specialization_graph_of: specialize::specialization_graph_provider,
796+
..*providers
797+
};
798+
}

src/librustc/traits/object_safety.rs

+6-19
Original file line numberDiff line numberDiff line change
@@ -77,25 +77,6 @@ pub enum MethodViolationCode {
7777
}
7878

7979
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
80-
pub fn is_object_safe(self, trait_def_id: DefId) -> bool {
81-
// Because we query yes/no results frequently, we keep a cache:
82-
let def = self.trait_def(trait_def_id);
83-
84-
let result = def.object_safety().unwrap_or_else(|| {
85-
let result = self.object_safety_violations(trait_def_id).is_empty();
86-
87-
// Record just a yes/no result in the cache; this is what is
88-
// queried most frequently. Note that this may overwrite a
89-
// previous result, but always with the same thing.
90-
def.set_object_safety(result);
91-
92-
result
93-
});
94-
95-
debug!("is_object_safe({:?}) = {}", trait_def_id, result);
96-
97-
result
98-
}
9980

10081
/// Returns the object safety violations that affect
10182
/// astconv - currently, Self in supertraits. This is needed
@@ -391,3 +372,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
391372
error
392373
}
393374
}
375+
376+
pub(super) fn is_object_safe_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
377+
trait_def_id: DefId)
378+
-> bool {
379+
tcx.object_safety_violations(trait_def_id).is_empty()
380+
}

0 commit comments

Comments
 (0)