]> git.lizzy.rs Git - rust.git/blob - src/librustc_traits/lowering.rs
Improve comments for Rule Implemented-From-Impl
[rust.git] / src / librustc_traits / lowering.rs
1 // Copyright 2018 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 rustc::hir::{self, ImplPolarity};
12 use rustc::hir::def_id::DefId;
13 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
14 use rustc::ty::{self, TyCtxt};
15 use rustc::traits::{QuantifierKind, Goal, DomainGoal, Clause, WhereClauseAtom};
16 use syntax::ast;
17 use rustc_data_structures::sync::Lrc;
18
19 trait Lower<T> {
20     /// Lower a rustc construction (e.g. `ty::TraitPredicate`) to a chalk-like type.
21     fn lower(&self) -> T;
22 }
23
24 impl<T, U> Lower<Vec<U>> for Vec<T> where T: Lower<U> {
25     fn lower(&self) -> Vec<U> {
26         self.iter().map(|item| item.lower()).collect()
27     }
28 }
29
30 impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::TraitPredicate<'tcx> {
31     fn lower(&self) -> WhereClauseAtom<'tcx> {
32         WhereClauseAtom::Implemented(*self)
33     }
34 }
35
36 impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::ProjectionPredicate<'tcx> {
37     fn lower(&self) -> WhereClauseAtom<'tcx> {
38         WhereClauseAtom::ProjectionEq(*self)
39     }
40 }
41
42 impl<'tcx, T> Lower<DomainGoal<'tcx>> for T where T: Lower<WhereClauseAtom<'tcx>> {
43     fn lower(&self) -> DomainGoal<'tcx> {
44         DomainGoal::Holds(self.lower())
45     }
46 }
47
48 impl<'tcx> Lower<DomainGoal<'tcx>> for ty::RegionOutlivesPredicate<'tcx> {
49     fn lower(&self) -> DomainGoal<'tcx> {
50         DomainGoal::RegionOutlives(*self)
51     }
52 }
53
54 impl<'tcx> Lower<DomainGoal<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
55     fn lower(&self) -> DomainGoal<'tcx> {
56         DomainGoal::TypeOutlives(*self)
57     }
58 }
59
60 /// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
61 /// lifetimes, e.g. `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
62 /// in that leaf-form (i.e. `Holds(Implemented(Binder<TraitPredicate>))` in the previous
63 /// example), we model them with quantified goals, e.g. as for the previous example:
64 /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
65 /// `Binder<Holds(Implemented(TraitPredicate))>`.
66 ///
67 /// Also, if `self` does not contain generic lifetimes, we can safely drop the binder and we
68 /// can directly lower to a leaf goal instead of a quantified goal.
69 impl<'tcx, T> Lower<Goal<'tcx>> for ty::Binder<T>
70     where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx> + Copy
71 {
72     fn lower(&self) -> Goal<'tcx> {
73         match self.no_late_bound_regions() {
74             Some(p) => p.lower().into(),
75             None => Goal::Quantified(
76                 QuantifierKind::Universal,
77                 Box::new(self.map_bound(|p| p.lower().into()))
78             ),
79         }
80     }
81 }
82
83 impl<'tcx> Lower<Goal<'tcx>> for ty::Predicate<'tcx> {
84     fn lower(&self) -> Goal<'tcx> {
85         use rustc::ty::Predicate::*;
86
87         match self {
88             Trait(predicate) => predicate.lower(),
89             RegionOutlives(predicate) => predicate.lower(),
90             TypeOutlives(predicate) => predicate.lower(),
91             Projection(predicate) => predicate.lower(),
92             WellFormed(ty) => DomainGoal::WellFormedTy(*ty).into(),
93             ObjectSafe(..) |
94             ClosureKind(..) |
95             Subtype(..) |
96             ConstEvaluatable(..) => unimplemented!(),
97         }
98     }
99 }
100
101 crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
102     -> Lrc<Vec<Clause<'tcx>>>
103 {
104     let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
105     let item = tcx.hir.expect_item(node_id);
106     match item.node {
107         hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
108
109         // FIXME: other constructions e.g. traits, associated types...
110         _ => Lrc::new(vec![]),
111     }
112 }
113
114 fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
115     -> Lrc<Vec<Clause<'tcx>>>
116 {
117     if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
118         return Lrc::new(vec![]);
119     }
120
121     // Rule Implemented-From-Impl (see rustc guide)
122     //
123     // `impl<P0..Pn> Trait<A1..An> for A0 where WC { .. }`
124     //
125     // ```
126     // forall<P0..Pn> {
127     //   Implemented(A0: Trait<A1..An>) :- WC
128     // }
129     // ```
130
131     let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
132     // `Implemented(A0: Trait<A1..An>)`
133     let trait_pred = ty::TraitPredicate { trait_ref }.lower();
134      // `WC`
135     let where_clauses = tcx.predicates_of(def_id).predicates.lower();
136
137      // `Implemented(A0: Trait<A1..An>) :- WC`
138     let clause = Clause::Implies(where_clauses, trait_pred);
139     Lrc::new(vec![clause])
140 }
141
142 pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
143     if !tcx.features().rustc_attrs {
144         return;
145     }
146
147     let mut visitor = ClauseDumper { tcx };
148     tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
149 }
150
151 struct ClauseDumper<'a, 'tcx: 'a> {
152     tcx: TyCtxt<'a, 'tcx, 'tcx>,
153 }
154
155 impl <'a, 'tcx> ClauseDumper<'a, 'tcx > {
156     fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
157         let def_id = self.tcx.hir.local_def_id(node_id);
158         for attr in attrs {
159             if attr.check_name("rustc_dump_program_clauses") {
160                 let clauses = self.tcx.program_clauses_for(def_id);
161                 for clause in &*clauses {
162                     self.tcx.sess.struct_span_err(attr.span, &format!("{}", clause)).emit();
163                 }
164             }
165         }
166     }
167 }
168
169 impl<'a, 'tcx> Visitor<'tcx> for ClauseDumper<'a, 'tcx> {
170     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
171         NestedVisitorMap::OnlyBodies(&self.tcx.hir)
172     }
173
174     fn visit_item(&mut self, item: &'tcx hir::Item) {
175         self.process_attrs(item.id, &item.attrs);
176         intravisit::walk_item(self, item);
177     }
178
179     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
180         self.process_attrs(trait_item.id, &trait_item.attrs);
181         intravisit::walk_trait_item(self, trait_item);
182     }
183
184     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
185         self.process_attrs(impl_item.id, &impl_item.attrs);
186         intravisit::walk_impl_item(self, impl_item);
187     }
188
189     fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
190         self.process_attrs(s.id, &s.attrs);
191         intravisit::walk_struct_field(self, s);
192     }
193 }