]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/trait_def.rs
Remove interior mutability from TraitDef by turning fields into queries.
[rust.git] / src / librustc / ty / trait_def.rs
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.
4 //
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.
10
11 use hir::def_id::DefId;
12 use traits::specialization_graph;
13 use ty::fast_reject;
14 use ty::fold::TypeFoldable;
15 use ty::{Ty, TyCtxt};
16 use std::rc::Rc;
17 use hir;
18
19 /// A trait's definition with type information.
20 pub struct TraitDef {
21     pub def_id: DefId,
22
23     pub unsafety: hir::Unsafety,
24
25     /// If `true`, then this trait had the `#[rustc_paren_sugar]`
26     /// attribute, indicating that it should be used with `Foo()`
27     /// sugar. This is a temporary thing -- eventually any trait will
28     /// be usable with the sugar (or without it).
29     pub paren_sugar: bool,
30
31     pub has_default_impl: bool,
32
33     /// The ICH of this trait's DefPath, cached here so it doesn't have to be
34     /// recomputed all the time.
35     pub def_path_hash: u64,
36 }
37
38 impl<'a, 'gcx, 'tcx> TraitDef {
39     pub fn new(def_id: DefId,
40                unsafety: hir::Unsafety,
41                paren_sugar: bool,
42                has_default_impl: bool,
43                def_path_hash: u64)
44                -> TraitDef {
45         TraitDef {
46             def_id,
47             paren_sugar,
48             unsafety,
49             has_default_impl,
50             def_path_hash,
51         }
52     }
53
54     pub fn ancestors(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
55                      of_impl: DefId)
56                      -> specialization_graph::Ancestors {
57         specialization_graph::ancestors(tcx, self.def_id, of_impl)
58     }
59
60     pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
61         for &impl_def_id in tcx.trait_impls_of(self.def_id).iter() {
62             f(impl_def_id);
63         }
64     }
65
66     /// Iterate over every impl that could possibly match the
67     /// self-type `self_ty`.
68     pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
69                                                    tcx: TyCtxt<'a, 'gcx, 'tcx>,
70                                                    self_ty: Ty<'tcx>,
71                                                    mut f: F)
72     {
73         // simplify_type(.., false) basically replaces type parameters and
74         // projections with infer-variables. This is, of course, done on
75         // the impl trait-ref when it is instantiated, but not on the
76         // predicate trait-ref which is passed here.
77         //
78         // for example, if we match `S: Copy` against an impl like
79         // `impl<T:Copy> Copy for Option<T>`, we replace the type variable
80         // in `Option<T>` with an infer variable, to `Option<_>` (this
81         // doesn't actually change fast_reject output), but we don't
82         // replace `S` with anything - this impl of course can't be
83         // selected, and as there are hundreds of similar impls,
84         // considering them would significantly harm performance.
85         let relevant_impls = if let Some(simplified_self_ty) =
86                 fast_reject::simplify_type(tcx, self_ty, true) {
87             tcx.relevant_trait_impls_for((self.def_id, simplified_self_ty))
88         } else {
89             tcx.trait_impls_of(self.def_id)
90         };
91
92         for &impl_def_id in relevant_impls.iter() {
93             f(impl_def_id);
94         }
95     }
96 }
97
98 // Query provider for `trait_impls_of`.
99 pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
100                                                 trait_id: DefId)
101                                                 -> Rc<Vec<DefId>> {
102     let mut impls = if trait_id.is_local() {
103         // Traits defined in the current crate can't have impls in upstream
104         // crates, so we don't bother querying the cstore.
105         Vec::new()
106     } else {
107         tcx.sess.cstore.implementations_of_trait(Some(trait_id))
108     };
109
110     impls.extend(tcx.hir
111                     .trait_impls(trait_id)
112                     .iter()
113                     .map(|&node_id| tcx.hir.local_def_id(node_id))
114                     .filter(|&impl_def_id| {
115                         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
116                         !trait_ref.references_error()
117                     }));
118     Rc::new(impls)
119 }
120
121 // Query provider for `relevant_trait_impls_for`.
122 pub(super) fn relevant_trait_impls_provider<'a, 'tcx>(
123     tcx: TyCtxt<'a, 'tcx, 'tcx>,
124     (trait_id, self_ty): (DefId, fast_reject::SimplifiedType))
125     -> Rc<Vec<DefId>>
126 {
127     let all_trait_impls = tcx.trait_impls_of(trait_id);
128
129     let relevant: Vec<DefId> = all_trait_impls
130         .iter()
131         .map(|&impl_def_id| impl_def_id)
132         .filter(|&impl_def_id| {
133             let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
134             let impl_simple_self_ty = fast_reject::simplify_type(tcx,
135                                                                  impl_trait_ref.self_ty(),
136                                                                  false);
137             if let Some(impl_simple_self_ty) = impl_simple_self_ty {
138                 impl_simple_self_ty == self_ty
139             } else {
140                 // blanket impl (?)
141                 true
142             }
143         })
144         .collect();
145
146     if all_trait_impls.len() == relevant.len() {
147         // If we didn't filter anything out, re-use the existing vec.
148         all_trait_impls
149     } else {
150         Rc::new(relevant)
151     }
152 }