Skip to content

Commit 8da2fe8

Browse files
Remove interior mutability from TraitDef by turning fields into queries.
1 parent 77b7df3 commit 8da2fe8

File tree

18 files changed

+300
-453
lines changed

18 files changed

+300
-453
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 4 additions & 0 deletions
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
@@ -264,6 +266,8 @@ impl<D: Clone + Debug> DepNode<D> {
264266
UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
265267
ConstEval(ref d) => op(d).map(ConstEval),
266268
SymbolName(ref d) => op(d).map(SymbolName),
269+
SpecializationGraph(ref d) => op(d).map(SpecializationGraph),
270+
ObjectSafety(ref d) => op(d).map(ObjectSafety),
267271
TraitImpls(ref d) => op(d).map(TraitImpls),
268272
AllLocalTraitImpls => Some(AllLocalTraitImpls),
269273
TraitItems(ref d) => op(d).map(TraitItems),

src/librustc/diagnostics.rs

Lines changed: 61 additions & 0 deletions
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/traits/mod.rs

Lines changed: 16 additions & 2 deletions
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

Lines changed: 6 additions & 19 deletions
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+
}

src/librustc/traits/project.rs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,23 +1320,10 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
13201320
let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
13211321
let trait_def = selcx.tcx().trait_def(trait_def_id);
13221322

1323-
if !trait_def.is_complete(selcx.tcx()) {
1324-
let impl_node = specialization_graph::Node::Impl(impl_def_id);
1325-
for item in impl_node.items(selcx.tcx()) {
1326-
if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
1327-
return Some(specialization_graph::NodeItem {
1328-
node: specialization_graph::Node::Impl(impl_def_id),
1329-
item: item,
1330-
});
1331-
}
1332-
}
1333-
None
1334-
} else {
1335-
trait_def
1336-
.ancestors(impl_def_id)
1337-
.defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
1338-
.next()
1339-
}
1323+
trait_def
1324+
.ancestors(selcx.tcx(), impl_def_id)
1325+
.defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
1326+
.next()
13401327
}
13411328

13421329
// # Cache

src/librustc/traits/specialize/mod.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use ty::subst::{Subst, Substs};
2727
use traits::{self, Reveal, ObligationCause};
2828
use ty::{self, TyCtxt, TypeFoldable};
2929
use syntax_pos::DUMMY_SP;
30+
use std::rc::Rc;
3031

3132
pub mod specialization_graph;
3233

@@ -118,7 +119,7 @@ pub fn find_associated_item<'a, 'tcx>(
118119
let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
119120
let trait_def = tcx.trait_def(trait_def_id);
120121

121-
let ancestors = trait_def.ancestors(impl_data.impl_def_id);
122+
let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id);
122123
match ancestors.defs(tcx, item.name, item.kind).next() {
123124
Some(node_item) => {
124125
let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
@@ -285,3 +286,50 @@ impl SpecializesCache {
285286
self.map.insert((a, b), result);
286287
}
287288
}
289+
290+
// Query provider for `specialization_graph_of`.
291+
pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
292+
trait_id: DefId)
293+
-> Rc<specialization_graph::Graph> {
294+
let mut sg = specialization_graph::Graph::new();
295+
296+
for &impl_def_id in tcx.trait_impls_of(trait_id).iter() {
297+
if impl_def_id.is_local() {
298+
// This is where impl overlap checking happens:
299+
let insert_result = sg.insert(tcx, impl_def_id);
300+
// Report error if there was one.
301+
if let Err(overlap) = insert_result {
302+
let mut err = struct_span_err!(tcx.sess,
303+
tcx.span_of_impl(impl_def_id).unwrap(),
304+
E0119,
305+
"conflicting implementations of trait `{}`{}:",
306+
overlap.trait_desc,
307+
overlap.self_desc.clone().map_or(String::new(),
308+
|ty| {
309+
format!(" for type `{}`", ty)
310+
}));
311+
312+
match tcx.span_of_impl(overlap.with_impl) {
313+
Ok(span) => {
314+
err.span_label(span, format!("first implementation here"));
315+
err.span_label(tcx.span_of_impl(impl_def_id).unwrap(),
316+
format!("conflicting implementation{}",
317+
overlap.self_desc
318+
.map_or(String::new(),
319+
|ty| format!(" for `{}`", ty))));
320+
}
321+
Err(cname) => {
322+
err.note(&format!("conflicting implementation in crate `{}`", cname));
323+
}
324+
}
325+
326+
err.emit();
327+
}
328+
} else {
329+
let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
330+
sg.record_impl_from_cstore(tcx, parent, impl_def_id)
331+
}
332+
}
333+
334+
Rc::new(sg)
335+
}

src/librustc/traits/specialize/specialization_graph.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ use super::{OverlapError, specializes};
1212

1313
use hir::def_id::DefId;
1414
use traits::{self, Reveal};
15-
use ty::{self, TyCtxt, TraitDef, TypeFoldable};
15+
use ty::{self, TyCtxt, TypeFoldable};
1616
use ty::fast_reject::{self, SimplifiedType};
17+
use std::rc::Rc;
1718
use syntax::ast::Name;
1819
use util::nodemap::{DefIdMap, FxHashMap};
1920

@@ -301,18 +302,19 @@ impl<'a, 'gcx, 'tcx> Node {
301302
}
302303
}
303304

304-
pub struct Ancestors<'a> {
305-
trait_def: &'a TraitDef,
305+
pub struct Ancestors {
306+
trait_def_id: DefId,
307+
specialization_graph: Rc<Graph>,
306308
current_source: Option<Node>,
307309
}
308310

309-
impl<'a> Iterator for Ancestors<'a> {
311+
impl Iterator for Ancestors {
310312
type Item = Node;
311313
fn next(&mut self) -> Option<Node> {
312314
let cur = self.current_source.take();
313315
if let Some(Node::Impl(cur_impl)) = cur {
314-
let parent = self.trait_def.specialization_graph.borrow().parent(cur_impl);
315-
if parent == self.trait_def.def_id {
316+
let parent = self.specialization_graph.parent(cur_impl);
317+
if parent == self.trait_def_id {
316318
self.current_source = Some(Node::Trait(parent));
317319
} else {
318320
self.current_source = Some(Node::Impl(parent));
@@ -336,7 +338,7 @@ impl<T> NodeItem<T> {
336338
}
337339
}
338340

339-
impl<'a, 'gcx, 'tcx> Ancestors<'a> {
341+
impl<'a, 'gcx, 'tcx> Ancestors {
340342
/// Search the items from the given ancestors, returning each definition
341343
/// with the given name and the given kind.
342344
#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
@@ -351,9 +353,14 @@ impl<'a, 'gcx, 'tcx> Ancestors<'a> {
351353

352354
/// Walk up the specialization ancestors of a given impl, starting with that
353355
/// impl itself.
354-
pub fn ancestors<'a>(trait_def: &'a TraitDef, start_from_impl: DefId) -> Ancestors<'a> {
356+
pub fn ancestors(tcx: TyCtxt,
357+
trait_def_id: DefId,
358+
start_from_impl: DefId)
359+
-> Ancestors {
360+
let specialization_graph = tcx.specialization_graph_of(trait_def_id);
355361
Ancestors {
356-
trait_def: trait_def,
362+
trait_def_id,
363+
specialization_graph,
357364
current_source: Some(Node::Impl(start_from_impl)),
358365
}
359366
}

src/librustc/ty/maps.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ use middle::region::RegionMaps;
1818
use mir;
1919
use mir::transform::{MirSuite, MirPassIndex};
2020
use session::CompileResult;
21+
use traits::specialization_graph;
2122
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
2223
use ty::item_path;
2324
use ty::steal::Steal;
2425
use ty::subst::Substs;
26+
use ty::fast_reject::SimplifiedType;
2527
use util::nodemap::{DefIdSet, NodeSet};
2628

2729
use rustc_data_structures::indexed_vec::IndexVec;
@@ -98,6 +100,15 @@ impl Key for (CrateNum, DefId) {
98100
}
99101
}
100102

103+
impl Key for (DefId, SimplifiedType) {
104+
fn map_crate(&self) -> CrateNum {
105+
self.0.krate
106+
}
107+
fn default_span(&self, tcx: TyCtxt) -> Span {
108+
self.0.default_span(tcx)
109+
}
110+
}
111+
101112
impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) {
102113
fn map_crate(&self) -> CrateNum {
103114
self.0.krate
@@ -391,6 +402,24 @@ impl<'tcx> QueryDescription for queries::is_mir_available<'tcx> {
391402
}
392403
}
393404

405+
impl<'tcx> QueryDescription for queries::trait_impls_of<'tcx> {
406+
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
407+
format!("trait impls of `{}`", tcx.item_path_str(def_id))
408+
}
409+
}
410+
411+
impl<'tcx> QueryDescription for queries::relevant_trait_impls_for<'tcx> {
412+
fn describe(tcx: TyCtxt, (def_id, ty): (DefId, SimplifiedType)) -> String {
413+
format!("relevant impls for: `({}, {:?})`", tcx.item_path_str(def_id), ty)
414+
}
415+
}
416+
417+
impl<'tcx> QueryDescription for queries::is_object_safe<'tcx> {
418+
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
419+
format!("determine object safety of trait `{}`", tcx.item_path_str(def_id))
420+
}
421+
}
422+
394423
macro_rules! define_maps {
395424
(<$tcx:tt>
396425
$($(#[$attr:meta])*
@@ -820,6 +849,13 @@ define_maps! { <'tcx>
820849
[] item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> Rc<BTreeMap<hir::BodyId, hir::Body>>,
821850
[] const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
822851
[] is_mir_available: IsMirAvailable(DefId) -> bool,
852+
853+
[] trait_impls_of: TraitImpls(DefId) -> Rc<Vec<DefId>>,
854+
// Note that TraitDef::for_each_relevant_impl() will do type simplication for you.
855+
[] relevant_trait_impls_for: relevant_trait_impls_for((DefId, SimplifiedType))
856+
-> Rc<Vec<DefId>>,
857+
[] specialization_graph_of: SpecializationGraph(DefId) -> Rc<specialization_graph::Graph>,
858+
[] is_object_safe: ObjectSafety(DefId) -> bool,
823859
}
824860

825861
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@@ -859,3 +895,7 @@ fn mir_keys(_: CrateNum) -> DepNode<DefId> {
859895
fn crate_variances(_: CrateNum) -> DepNode<DefId> {
860896
DepNode::CrateVariances
861897
}
898+
899+
fn relevant_trait_impls_for((def_id, _): (DefId, SimplifiedType)) -> DepNode<DefId> {
900+
DepNode::TraitImpls(def_id)
901+
}

0 commit comments

Comments
 (0)