1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use dep_graph::DepNode;
12 use middle::def_id::DefId;
14 use middle::ty::fast_reject;
15 use middle::ty::{Ty, TyCtxt};
16 use std::borrow::{Borrow};
17 use std::cell::{Cell, Ref, RefCell};
18 use syntax::ast::Name;
20 use util::nodemap::FnvHashMap;
22 /// As `TypeScheme` but for a trait ref.
23 pub struct TraitDef<'tcx> {
24 pub unsafety: hir::Unsafety,
26 /// If `true`, then this trait had the `#[rustc_paren_sugar]`
27 /// attribute, indicating that it should be used with `Foo()`
28 /// sugar. This is a temporary thing -- eventually any trait wil
29 /// be usable with the sugar (or without it).
30 pub paren_sugar: bool,
32 /// Generic type definitions. Note that `Self` is listed in here
33 /// as having a single bound, the trait itself (e.g., in the trait
34 /// `Eq`, there is a single bound `Self : Eq`). This is so that
35 /// default methods get to assume that the `Self` parameters
36 /// implements the trait.
37 pub generics: ty::Generics<'tcx>,
39 pub trait_ref: ty::TraitRef<'tcx>,
41 /// A list of the associated types defined in this trait. Useful
42 /// for resolving `X::Foo` type markers.
43 pub associated_type_names: Vec<Name>,
45 // Impls of this trait. To allow for quicker lookup, the impls are indexed
46 // by a simplified version of their Self type: impls with a simplifiable
47 // Self are stored in nonblanket_impls keyed by it, while all other impls
48 // are stored in blanket_impls.
50 // These lists are tracked by `DepNode::TraitImpls`; we don't use
51 // a DepTrackingMap but instead have the `TraitDef` insert the
52 // required reads/writes.
54 /// Impls of the trait.
55 nonblanket_impls: RefCell<
56 FnvHashMap<fast_reject::SimplifiedType, Vec<DefId>>
59 /// Blanket impls associated with the trait.
60 blanket_impls: RefCell<Vec<DefId>>,
62 /// The specialization order for impls of this trait.
63 pub specialization_graph: RefCell<traits::SpecializationGraph>,
66 pub flags: Cell<TraitFlags>
69 impl<'tcx> TraitDef<'tcx> {
70 pub fn new(unsafety: hir::Unsafety,
72 generics: ty::Generics<'tcx>,
73 trait_ref: ty::TraitRef<'tcx>,
74 associated_type_names: Vec<Name>)
77 paren_sugar: paren_sugar,
81 associated_type_names: associated_type_names,
82 nonblanket_impls: RefCell::new(FnvHashMap()),
83 blanket_impls: RefCell::new(vec![]),
84 flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
85 specialization_graph: RefCell::new(traits::SpecializationGraph::new()),
89 pub fn def_id(&self) -> DefId {
93 // returns None if not yet calculated
94 pub fn object_safety(&self) -> Option<bool> {
95 if self.flags.get().intersects(TraitFlags::OBJECT_SAFETY_VALID) {
96 Some(self.flags.get().intersects(TraitFlags::IS_OBJECT_SAFE))
102 pub fn set_object_safety(&self, is_safe: bool) {
103 assert!(self.object_safety().map(|cs| cs == is_safe).unwrap_or(true));
105 self.flags.get() | if is_safe {
106 TraitFlags::OBJECT_SAFETY_VALID | TraitFlags::IS_OBJECT_SAFE
108 TraitFlags::OBJECT_SAFETY_VALID
113 fn write_trait_impls(&self, tcx: &TyCtxt<'tcx>) {
114 tcx.dep_graph.write(DepNode::TraitImpls(self.trait_ref.def_id));
117 fn read_trait_impls(&self, tcx: &TyCtxt<'tcx>) {
118 tcx.dep_graph.read(DepNode::TraitImpls(self.trait_ref.def_id));
121 /// Records a basic trait-to-implementation mapping.
123 /// Returns `true` iff the impl has not previously been recorded.
124 fn record_impl(&self,
127 impl_trait_ref: TraitRef<'tcx>) -> bool {
128 debug!("TraitDef::record_impl for {:?}, from {:?}",
129 self, impl_trait_ref);
131 // We don't want to borrow_mut after we already populated all impls,
132 // so check if an impl is present with an immutable borrow first.
133 if let Some(sty) = fast_reject::simplify_type(tcx,
134 impl_trait_ref.self_ty(), false) {
135 if let Some(is) = self.nonblanket_impls.borrow().get(&sty) {
136 if is.contains(&impl_def_id) {
137 return false; // duplicate - skip
141 self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id)
143 if self.blanket_impls.borrow().contains(&impl_def_id) {
144 return false; // duplicate - skip
146 self.blanket_impls.borrow_mut().push(impl_def_id)
152 /// Records a trait-to-implementation mapping for a crate-local impl.
153 pub fn record_local_impl(&self,
156 impl_trait_ref: TraitRef<'tcx>) {
157 self.record_impl(tcx, impl_def_id, impl_trait_ref);
160 /// Records a trait-to-implementation mapping for a non-local impl.
162 /// The `parent_impl` is the immediately-less-specialized impl, or the
163 /// trait's def ID if the impl is maximally-specialized -- information that
164 /// should be pulled from the metadata.
165 pub fn record_remote_impl(&self,
168 impl_trait_ref: TraitRef<'tcx>,
169 parent_impl: DefId) {
170 // if the impl has not previously been recorded
171 if self.record_impl(tcx, impl_def_id, impl_trait_ref) {
172 // if the impl is non-local, it's placed directly into the
173 // specialization graph using parent information drawn from metadata.
174 self.specialization_graph.borrow_mut()
175 .record_impl_from_cstore(parent_impl, impl_def_id)
179 /// Adds a local impl into the specialization graph, returning an error with
180 /// overlap information if the impl overlaps but does not specialize an
182 pub fn add_impl_for_specialization(&self,
185 impl_trait_ref: TraitRef<'tcx>)
186 -> Result<(), traits::Overlap<'tcx>> {
187 assert!(impl_def_id.is_local());
189 self.specialization_graph.borrow_mut()
190 .insert(tcx, impl_def_id, impl_trait_ref)
193 pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: &TyCtxt<'tcx>, mut f: F) {
194 self.read_trait_impls(tcx);
195 tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
197 for &impl_def_id in self.blanket_impls.borrow().iter() {
201 for v in self.nonblanket_impls.borrow().values() {
202 for &impl_def_id in v {
208 /// Iterate over every impl that could possibly match the
209 /// self-type `self_ty`.
210 pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
215 self.read_trait_impls(tcx);
217 tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
219 for &impl_def_id in self.blanket_impls.borrow().iter() {
223 // simplify_type(.., false) basically replaces type parameters and
224 // projections with infer-variables. This is, of course, done on
225 // the impl trait-ref when it is instantiated, but not on the
226 // predicate trait-ref which is passed here.
228 // for example, if we match `S: Copy` against an impl like
229 // `impl<T:Copy> Copy for Option<T>`, we replace the type variable
230 // in `Option<T>` with an infer variable, to `Option<_>` (this
231 // doesn't actually change fast_reject output), but we don't
232 // replace `S` with anything - this impl of course can't be
233 // selected, and as there are hundreds of similar impls,
234 // considering them would significantly harm performance.
235 if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) {
236 if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) {
237 for &impl_def_id in impls {
242 for v in self.nonblanket_impls.borrow().values() {
243 for &impl_def_id in v {
250 pub fn borrow_impl_lists<'s>(&'s self, tcx: &TyCtxt<'tcx>)
251 -> (Ref<'s, Vec<DefId>>,
252 Ref<'s, FnvHashMap<fast_reject::SimplifiedType, Vec<DefId>>>) {
253 self.read_trait_impls(tcx);
254 (self.blanket_impls.borrow(), self.nonblanket_impls.borrow())
260 flags TraitFlags: u32 {
261 const NO_TRAIT_FLAGS = 0,
262 const HAS_DEFAULT_IMPL = 1 << 0,
263 const IS_OBJECT_SAFE = 1 << 1,
264 const OBJECT_SAFETY_VALID = 1 << 2,
265 const IMPLS_VALID = 1 << 3,