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, Slice, TyCtxt};
15 use rustc::ty::subst::Substs;
16 use rustc::traits::{WhereClauseAtom, PolyDomainGoal, DomainGoal, ProgramClause, Clause, Goal};
18 use rustc_data_structures::sync::Lrc;
23 /// Lower a rustc construction (e.g. `ty::TraitPredicate`) to a chalk-like type.
27 impl<T, U> Lower<Vec<U>> for Vec<T> where T: Lower<U> {
28 fn lower(&self) -> Vec<U> {
29 self.iter().map(|item| item.lower()).collect()
33 impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::TraitPredicate<'tcx> {
34 fn lower(&self) -> WhereClauseAtom<'tcx> {
35 WhereClauseAtom::Implemented(*self)
39 impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::ProjectionPredicate<'tcx> {
40 fn lower(&self) -> WhereClauseAtom<'tcx> {
41 WhereClauseAtom::ProjectionEq(*self)
45 impl<'tcx, T> Lower<DomainGoal<'tcx>> for T where T: Lower<WhereClauseAtom<'tcx>> {
46 fn lower(&self) -> DomainGoal<'tcx> {
47 DomainGoal::Holds(self.lower())
51 impl<'tcx> Lower<DomainGoal<'tcx>> for ty::RegionOutlivesPredicate<'tcx> {
52 fn lower(&self) -> DomainGoal<'tcx> {
53 DomainGoal::RegionOutlives(*self)
57 impl<'tcx> Lower<DomainGoal<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
58 fn lower(&self) -> DomainGoal<'tcx> {
59 DomainGoal::TypeOutlives(*self)
63 /// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
64 /// lifetimes, e.g. `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
65 /// in that leaf-form (i.e. `Holds(Implemented(Binder<TraitPredicate>))` in the previous
66 /// example), we model them with quantified domain goals, e.g. as for the previous example:
67 /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
68 /// `Binder<Holds(Implemented(TraitPredicate))>`.
69 impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
70 where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>
72 fn lower(&self) -> PolyDomainGoal<'tcx> {
73 self.map_bound_ref(|p| p.lower())
77 impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
78 fn lower(&self) -> PolyDomainGoal<'tcx> {
79 use rustc::ty::Predicate::*;
82 Trait(predicate) => predicate.lower(),
83 RegionOutlives(predicate) => predicate.lower(),
84 TypeOutlives(predicate) => predicate.lower(),
85 Projection(predicate) => predicate.lower(),
86 WellFormed(ty) => ty::Binder::dummy(DomainGoal::WellFormedTy(*ty)),
90 ConstEvaluatable(..) => unimplemented!(),
95 /// Transforms an existing goal into a FromEnv goal.
97 /// Used for lowered where clauses (see rustc guide).
98 trait IntoFromEnvGoal {
99 fn into_from_env_goal(self) -> Self;
102 impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
103 fn into_from_env_goal(self) -> DomainGoal<'tcx> {
104 use self::DomainGoal::*;
106 Holds(wc_atom) => FromEnv(wc_atom),
112 TypeOutlives(..) => self,
117 crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
118 -> Lrc<&'tcx Slice<Clause<'tcx>>>
120 let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
121 let node = tcx.hir.find(node_id).unwrap();
123 hir::map::Node::NodeItem(item) => match item.node {
124 hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
125 hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
126 _ => Lrc::new(vec![]),
128 hir::map::Node::NodeImplItem(item) => {
129 if let hir::ImplItemKind::Type(..) = item.node {
130 program_clauses_for_associated_type_value(tcx, def_id)
136 // FIXME: other constructions e.g. traits, associated types...
137 _ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
141 fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
142 -> Lrc<&'tcx Slice<Clause<'tcx>>>
144 // `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
146 // Rule Implemented-From-Env (see rustc guide)
149 // forall<Self, P1..Pn> {
150 // Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
154 // `Self: Trait<P1..Pn>`
155 let trait_pred = ty::TraitPredicate {
156 trait_ref: ty::TraitRef {
158 substs: Substs::identity_for_item(tcx, def_id)
161 // `FromEnv(Self: Trait<P1..Pn>)`
162 let from_env = Goal::from(DomainGoal::FromEnv(trait_pred.lower()));
163 // `Implemented(Self: Trait<P1..Pn>)`
164 let impl_trait = DomainGoal::Holds(WhereClauseAtom::Implemented(trait_pred));
166 // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
167 let implemented_from_env = ProgramClause {
169 hypotheses: tcx.mk_goals(iter::once(from_env)),
171 let clauses = iter::once(
172 Clause::ForAll(ty::Binder::dummy(implemented_from_env))
175 // Rule Implied-Bound-From-Trait
177 // For each where clause WC:
179 // forall<Self, P1..Pn> {
180 // FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn)
184 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
185 // FIXME: Remove the [1..] slice; this is a hack because the query
186 // predicates_of currently includes the trait itself (`Self: Trait<P1..Pn>`).
187 let where_clauses = &tcx.predicates_of(def_id).predicates;
188 let implied_bound_clauses =
189 where_clauses[1..].into_iter()
190 .map(|wc| implied_bound_from_trait(tcx, trait_pred, wc));
192 Lrc::new(tcx.mk_clauses(clauses.chain(implied_bound_clauses)))
195 /// For a given `where_clause`, returns a clause `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`.
196 fn implied_bound_from_trait<'a, 'tcx>(
197 tcx: TyCtxt<'a, 'tcx, 'tcx>,
198 trait_pred: ty::TraitPredicate<'tcx>,
199 where_clause: &ty::Predicate<'tcx>,
201 // `FromEnv(Self: Trait<P1..Pn>)`
202 let impl_trait = DomainGoal::FromEnv(WhereClauseAtom::Implemented(trait_pred));
204 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
206 where_clause.lower().map_bound(|goal| ProgramClause {
207 goal: goal.into_from_env_goal(),
208 hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))),
213 fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
214 -> Lrc<&'tcx Slice<Clause<'tcx>>>
216 if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
217 return Lrc::new(tcx.mk_clauses(iter::empty::<Clause>()));
220 // Rule Implemented-From-Impl (see rustc guide)
222 // `impl<P0..Pn> Trait<A1..An> for A0 where WC { .. }`
226 // Implemented(A0: Trait<A1..An>) :- WC
230 let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
231 // `Implemented(A0: Trait<A1..An>)`
232 let trait_pred = ty::TraitPredicate { trait_ref }.lower();
234 let where_clauses = tcx.predicates_of(def_id).predicates.lower();
236 // `Implemented(A0: Trait<A1..An>) :- WC`
237 let clause = ProgramClause {
239 hypotheses: tcx.mk_goals(
240 where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
243 Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))))
246 pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
247 tcx: TyCtxt<'a, 'tcx, 'tcx>,
249 ) -> Lrc<Vec<Clause<'tcx>>> {
250 // Rule Normalize-From-Impl (see rustc guide)
252 // ```impl<P0..Pn> Trait<A1..An> for A0
255 // type AssocType<Pn+1..Pm> where WC1 = T;
260 // forall<Pn+1..Pm> {
261 // Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
267 let item = tcx.associated_item(item_id);
268 debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
269 let impl_id = if let ty::AssociatedItemContainer::ImplContainer(impl_id) = item.container {
274 // `A0 as Trait<A1..An>`
275 let trait_ref = tcx.impl_trait_ref(impl_id).unwrap();
277 let ty = tcx.type_of(item_id);
279 let impl_where_clauses = tcx.predicates_of(impl_id).predicates.lower();
281 let item_where_clauses = tcx.predicates_of(item_id).predicates.lower();
283 let mut where_clauses = vec![];
284 where_clauses.extend(impl_where_clauses);
285 where_clauses.extend(item_where_clauses);
286 // `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
287 let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.name);
288 // `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
289 let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
290 // `Normalize(... -> T) :- WC && WC1`
291 let clause = Clause::Implies(where_clauses, normalize_goal);
292 Lrc::new(vec![clause])
295 pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
296 if !tcx.features().rustc_attrs {
300 let mut visitor = ClauseDumper { tcx };
301 tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
304 struct ClauseDumper<'a, 'tcx: 'a> {
305 tcx: TyCtxt<'a, 'tcx, 'tcx>,
308 impl<'a, 'tcx> ClauseDumper<'a, 'tcx > {
309 fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
310 let def_id = self.tcx.hir.local_def_id(node_id);
312 if attr.check_name("rustc_dump_program_clauses") {
313 let clauses = self.tcx.program_clauses_for(def_id);
314 for clause in *clauses {
315 // Skip the top-level binder for a less verbose output
316 let program_clause = match clause {
317 Clause::Implies(program_clause) => program_clause,
318 Clause::ForAll(program_clause) => program_clause.skip_binder(),
320 self.tcx.sess.struct_span_err(attr.span, &format!("{}", program_clause)).emit();
327 impl<'a, 'tcx> Visitor<'tcx> for ClauseDumper<'a, 'tcx> {
328 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
329 NestedVisitorMap::OnlyBodies(&self.tcx.hir)
332 fn visit_item(&mut self, item: &'tcx hir::Item) {
333 self.process_attrs(item.id, &item.attrs);
334 intravisit::walk_item(self, item);
337 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
338 self.process_attrs(trait_item.id, &trait_item.attrs);
339 intravisit::walk_trait_item(self, trait_item);
342 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
343 self.process_attrs(impl_item.id, &impl_item.attrs);
344 intravisit::walk_impl_item(self, impl_item);
347 fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
348 self.process_attrs(s.id, &s.attrs);
349 intravisit::walk_struct_field(self, s);