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.
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 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};
17 use rustc_data_structures::sync::Lrc;
20 /// Lower a rustc construction (e.g. `ty::TraitPredicate`) to a chalk-like type.
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()
30 impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::TraitPredicate<'tcx> {
31 fn lower(&self) -> WhereClauseAtom<'tcx> {
32 WhereClauseAtom::Implemented(*self)
36 impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::ProjectionPredicate<'tcx> {
37 fn lower(&self) -> WhereClauseAtom<'tcx> {
38 WhereClauseAtom::ProjectionEq(*self)
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())
48 impl<'tcx> Lower<DomainGoal<'tcx>> for ty::RegionOutlivesPredicate<'tcx> {
49 fn lower(&self) -> DomainGoal<'tcx> {
50 DomainGoal::RegionOutlives(*self)
54 impl<'tcx> Lower<DomainGoal<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
55 fn lower(&self) -> DomainGoal<'tcx> {
56 DomainGoal::TypeOutlives(*self)
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))>`.
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
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()))
83 impl<'tcx> Lower<Goal<'tcx>> for ty::Predicate<'tcx> {
84 fn lower(&self) -> Goal<'tcx> {
85 use rustc::ty::Predicate::*;
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(),
96 ConstEvaluatable(..) => unimplemented!(),
101 crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
102 -> Lrc<Vec<Clause<'tcx>>>
104 let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
105 let item = tcx.hir.expect_item(node_id);
107 hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
109 // FIXME: other constructions e.g. traits, associated types...
110 _ => Lrc::new(vec![]),
114 fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
115 -> Lrc<Vec<Clause<'tcx>>>
117 if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
118 return Lrc::new(vec![]);
121 // Rule Implemented-From-Impl
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();
129 let clause = Clause::Implies(where_clauses, trait_ref);
130 Lrc::new(vec![clause])
133 pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
134 if !tcx.features().rustc_attrs {
138 let mut visitor = ClauseDumper { tcx };
139 tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
142 struct ClauseDumper<'a, 'tcx: 'a> {
143 tcx: TyCtxt<'a, 'tcx, 'tcx>,
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);
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();
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)
165 fn visit_item(&mut self, item: &'tcx hir::Item) {
166 self.process_attrs(item.id, &item.attrs);
167 intravisit::walk_item(self, item);
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);
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);
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);