]> git.lizzy.rs Git - rust.git/blob - src/librustc_traits/lowering.rs
c9666f55d440e4480bfcd2d246235b10660a4d93
[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
122     //
123     // (see rustc guide)
124
125     let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
126     let trait_ref = ty::TraitPredicate { trait_ref }.lower();
127     let where_clauses = tcx.predicates_of(def_id).predicates.lower();
128
129     let clause = Clause::Implies(where_clauses, trait_ref);
130     Lrc::new(vec![clause])
131 }
132
133 pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
134     if !tcx.features().rustc_attrs {
135         return;
136     }
137
138     let mut visitor = ClauseDumper { tcx };
139     tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
140 }
141
142 struct ClauseDumper<'a, 'tcx: 'a> {
143     tcx: TyCtxt<'a, 'tcx, 'tcx>,
144 }
145
146 impl <'a, 'tcx> ClauseDumper<'a, 'tcx > {
147     fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
148         let def_id = self.tcx.hir.local_def_id(node_id);
149         for attr in attrs {
150             if attr.check_name("rustc_dump_program_clauses") {
151                 let clauses = self.tcx.program_clauses_for(def_id);
152                 for clause in &*clauses {
153                     self.tcx.sess.struct_span_err(attr.span, &format!("{}", clause)).emit();
154                 }
155             }
156         }
157     }
158 }
159
160 impl<'a, 'tcx> Visitor<'tcx> for ClauseDumper<'a, 'tcx> {
161     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
162         NestedVisitorMap::OnlyBodies(&self.tcx.hir)
163     }
164
165     fn visit_item(&mut self, item: &'tcx hir::Item) {
166         self.process_attrs(item.id, &item.attrs);
167         intravisit::walk_item(self, item);
168     }
169
170     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
171         self.process_attrs(trait_item.id, &trait_item.attrs);
172         intravisit::walk_trait_item(self, trait_item);
173     }
174
175     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
176         self.process_attrs(impl_item.id, &impl_item.attrs);
177         intravisit::walk_impl_item(self, impl_item);
178     }
179
180     fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
181         self.process_attrs(s.id, &s.attrs);
182         intravisit::walk_struct_field(self, s);
183     }
184 }