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.
13 use rustc::hir::def_id::DefId;
14 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
15 use rustc::hir::map::definitions::DefPathData;
16 use rustc::hir::{self, ImplPolarity};
25 ProgramClauseCategory,
29 use rustc::ty::query::Providers;
30 use rustc::ty::{self, List, TyCtxt};
31 use rustc::ty::subst::{Subst, Substs};
36 crate fn provide(p: &mut Providers) {
39 program_clauses_for_env: environment::program_clauses_for_env,
40 environment: environment::environment,
45 crate trait Lower<T> {
46 /// Lower a rustc construct (e.g. `ty::TraitPredicate`) to a chalk-like type.
50 impl<T, U> Lower<Vec<U>> for Vec<T>
54 fn lower(&self) -> Vec<U> {
55 self.iter().map(|item| item.lower()).collect()
59 impl<'tcx> Lower<WhereClause<'tcx>> for ty::TraitPredicate<'tcx> {
60 fn lower(&self) -> WhereClause<'tcx> {
61 WhereClause::Implemented(*self)
65 impl<'tcx> Lower<WhereClause<'tcx>> for ty::ProjectionPredicate<'tcx> {
66 fn lower(&self) -> WhereClause<'tcx> {
67 WhereClause::ProjectionEq(*self)
71 impl<'tcx> Lower<WhereClause<'tcx>> for ty::RegionOutlivesPredicate<'tcx> {
72 fn lower(&self) -> WhereClause<'tcx> {
73 WhereClause::RegionOutlives(*self)
77 impl<'tcx> Lower<WhereClause<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
78 fn lower(&self) -> WhereClause<'tcx> {
79 WhereClause::TypeOutlives(*self)
83 impl<'tcx, T> Lower<DomainGoal<'tcx>> for T
85 T: Lower<WhereClause<'tcx>>,
87 fn lower(&self) -> DomainGoal<'tcx> {
88 DomainGoal::Holds(self.lower())
92 /// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
93 /// lifetimes, e.g. `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
94 /// in that leaf-form (i.e. `Holds(Implemented(Binder<TraitPredicate>))` in the previous
95 /// example), we model them with quantified domain goals, e.g. as for the previous example:
96 /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
97 /// `Binder<Holds(Implemented(TraitPredicate))>`.
98 impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
100 T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>,
102 fn lower(&self) -> PolyDomainGoal<'tcx> {
103 self.map_bound_ref(|p| p.lower())
107 impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
108 fn lower(&self) -> PolyDomainGoal<'tcx> {
109 use rustc::ty::Predicate;
112 Predicate::Trait(predicate) => predicate.lower(),
113 Predicate::RegionOutlives(predicate) => predicate.lower(),
114 Predicate::TypeOutlives(predicate) => predicate.lower(),
115 Predicate::Projection(predicate) => predicate.lower(),
117 Predicate::WellFormed(..) |
118 Predicate::ObjectSafe(..) |
119 Predicate::ClosureKind(..) |
120 Predicate::Subtype(..) |
121 Predicate::ConstEvaluatable(..) => {
122 bug!("unexpected predicate {}", self)
128 /// Used for implied bounds related rules (see rustc guide).
129 trait IntoFromEnvGoal {
130 /// Transforms an existing goal into a `FromEnv` goal.
131 fn into_from_env_goal(self) -> Self;
134 /// Used for well-formedness related rules (see rustc guide).
135 trait IntoWellFormedGoal {
136 /// Transforms an existing goal into a `WellFormed` goal.
137 fn into_well_formed_goal(self) -> Self;
140 impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
141 fn into_from_env_goal(self) -> DomainGoal<'tcx> {
142 use self::WhereClause::*;
145 DomainGoal::Holds(Implemented(trait_ref)) => {
146 DomainGoal::FromEnv(FromEnv::Trait(trait_ref))
153 impl<'tcx> IntoWellFormedGoal for DomainGoal<'tcx> {
154 fn into_well_formed_goal(self) -> DomainGoal<'tcx> {
155 use self::WhereClause::*;
158 DomainGoal::Holds(Implemented(trait_ref)) => {
159 DomainGoal::WellFormed(WellFormed::Trait(trait_ref))
166 crate fn program_clauses_for<'a, 'tcx>(
167 tcx: TyCtxt<'a, 'tcx, 'tcx>,
170 match tcx.def_key(def_id).disambiguated_data.data {
171 DefPathData::Trait(_) => program_clauses_for_trait(tcx, def_id),
172 DefPathData::Impl => program_clauses_for_impl(tcx, def_id),
173 DefPathData::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx, def_id),
174 DefPathData::AssocTypeInTrait(..) => program_clauses_for_associated_type_def(tcx, def_id),
175 DefPathData::TypeNs(..) => program_clauses_for_type_def(tcx, def_id),
180 fn program_clauses_for_trait<'a, 'tcx>(
181 tcx: TyCtxt<'a, 'tcx, 'tcx>,
184 // `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
186 // Rule Implemented-From-Env (see rustc guide)
189 // forall<Self, P1..Pn> {
190 // Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
194 let bound_vars = Substs::bound_vars_for_item(tcx, def_id);
196 // `Self: Trait<P1..Pn>`
197 let trait_pred = ty::TraitPredicate {
198 trait_ref: ty::TraitRef {
204 // `Implemented(Self: Trait<P1..Pn>)`
205 let impl_trait: DomainGoal = trait_pred.lower();
207 // `FromEnv(Self: Trait<P1..Pn>)`
208 let from_env_goal = tcx.mk_goal(impl_trait.into_from_env_goal().into_goal());
209 let hypotheses = tcx.intern_goals(&[from_env_goal]);
211 // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
212 let implemented_from_env = ProgramClause {
215 category: ProgramClauseCategory::ImpliedBound,
218 let implemented_from_env = Clause::ForAll(ty::Binder::bind(implemented_from_env));
220 let predicates = &tcx.predicates_defined_on(def_id).predicates;
221 let where_clauses = &predicates
223 .map(|(wc, _)| wc.lower())
224 .map(|wc| wc.subst(tcx, bound_vars))
225 .collect::<Vec<_>>();
227 // Rule Implied-Bound-From-Trait
229 // For each where clause WC:
231 // forall<Self, P1..Pn> {
232 // FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn)
236 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
237 let implied_bound_clauses = where_clauses
241 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
243 // we move binders to the left
244 wc.map_bound(|goal| ProgramClause {
245 goal: goal.into_from_env_goal(),
247 // FIXME: As where clauses can only bind lifetimes for now,
248 // and that named bound regions have a def-id, it is safe
249 // to just inject `hypotheses` (which contains named vars bound at index `0`)
250 // into this binding level. This may change if we ever allow where clauses
251 // to bind types (e.g. for GATs things), because bound types only use a `BoundVar`
252 // index (no def-id).
255 category: ProgramClauseCategory::ImpliedBound,
258 .map(Clause::ForAll);
260 // Rule WellFormed-TraitRef
262 // Here `WC` denotes the set of all where clauses:
264 // forall<Self, P1..Pn> {
265 // WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)
270 let wf_conditions = where_clauses
272 .map(|wc| wc.map_bound(|goal| goal.into_well_formed_goal()));
274 // `WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
275 let wf_clause = ProgramClause {
276 goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)),
277 hypotheses: tcx.mk_goals(
278 iter::once(tcx.mk_goal(GoalKind::DomainGoal(impl_trait))).chain(
279 wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx)))
282 category: ProgramClauseCategory::WellFormed,
284 let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
287 iter::once(implemented_from_env)
288 .chain(implied_bound_clauses)
289 .chain(iter::once(wf_clause))
293 fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Clauses<'tcx> {
294 if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
295 return List::empty();
298 // Rule Implemented-From-Impl (see rustc guide)
300 // `impl<P0..Pn> Trait<A1..An> for A0 where WC { .. }`
304 // Implemented(A0: Trait<A1..An>) :- WC
308 let bound_vars = Substs::bound_vars_for_item(tcx, def_id);
310 let trait_ref = tcx.impl_trait_ref(def_id)
311 .expect("not an impl")
312 .subst(tcx, bound_vars);
314 // `Implemented(A0: Trait<A1..An>)`
315 let trait_pred = ty::TraitPredicate { trait_ref }.lower();
318 let predicates = &tcx.predicates_of(def_id).predicates;
319 let where_clauses = predicates
321 .map(|(wc, _)| wc.lower())
322 .map(|wc| wc.subst(tcx, bound_vars));
324 // `Implemented(A0: Trait<A1..An>) :- WC`
325 let clause = ProgramClause {
327 hypotheses: tcx.mk_goals(
329 .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
331 category: ProgramClauseCategory::Other,
333 tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::bind(clause))))
336 pub fn program_clauses_for_type_def<'a, 'tcx>(
337 tcx: TyCtxt<'a, 'tcx, 'tcx>,
340 // Rule WellFormed-Type
342 // `struct Ty<P1..Pn> where WC1, ..., WCm`
346 // WellFormed(Ty<...>) :- WC1, ..., WCm`
350 let bound_vars = Substs::bound_vars_for_item(tcx, def_id);
353 let ty = tcx.type_of(def_id).subst(tcx, bound_vars);
356 let where_clauses = tcx.predicates_of(def_id).predicates
358 .map(|(wc, _)| wc.lower())
359 .map(|wc| wc.subst(tcx, bound_vars))
360 .collect::<Vec<_>>();
362 // `WellFormed(Ty<...>) :- WC1, ..., WCm`
363 let well_formed_clause = ProgramClause {
364 goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
365 hypotheses: tcx.mk_goals(
369 .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
371 category: ProgramClauseCategory::WellFormed,
373 let well_formed_clause = Clause::ForAll(ty::Binder::bind(well_formed_clause));
375 // Rule Implied-Bound-From-Type
377 // For each where clause `WC`:
380 // FromEnv(WC) :- FromEnv(Ty<...>)
384 // `FromEnv(Ty<...>)`
385 let from_env_goal = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal());
386 let hypotheses = tcx.intern_goals(&[from_env_goal]);
388 // For each where clause `WC`:
389 let from_env_clauses = where_clauses
392 // `FromEnv(WC) :- FromEnv(Ty<...>)`
394 // move the binders to the left
395 wc.map_bound(|goal| ProgramClause {
396 goal: goal.into_from_env_goal(),
398 // FIXME: we inject `hypotheses` into this binding level,
399 // which may be incorrect in the future: see the FIXME in
400 // `program_clauses_for_trait`
403 category: ProgramClauseCategory::ImpliedBound,
407 .map(Clause::ForAll);
409 tcx.mk_clauses(iter::once(well_formed_clause).chain(from_env_clauses))
412 pub fn program_clauses_for_associated_type_def<'a, 'tcx>(
413 tcx: TyCtxt<'a, 'tcx, 'tcx>,
416 // Rule ProjectionEq-Placeholder
419 // trait Trait<P1..Pn> {
420 // type AssocType<Pn+1..Pm>;
424 // `ProjectionEq` can succeed by skolemizing, see "associated type"
427 // forall<Self, P1..Pn, Pn+1..Pm> {
429 // <Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> =
430 // (Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>
435 let item = tcx.associated_item(item_id);
436 debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
437 let trait_id = match item.container {
438 ty::AssociatedItemContainer::TraitContainer(trait_id) => trait_id,
439 _ => bug!("not an trait container"),
442 let trait_bound_vars = Substs::bound_vars_for_item(tcx, trait_id);
443 let trait_ref = ty::TraitRef {
445 substs: trait_bound_vars,
448 let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
449 let placeholder_ty = tcx.mk_ty(ty::UnnormalizedProjection(projection_ty));
450 let projection_eq = WhereClause::ProjectionEq(ty::ProjectionPredicate {
455 let projection_eq_clause = ProgramClause {
456 goal: DomainGoal::Holds(projection_eq),
457 hypotheses: ty::List::empty(),
458 category: ProgramClauseCategory::Other,
460 let projection_eq_clause = Clause::ForAll(ty::Binder::bind(projection_eq_clause));
462 // Rule WellFormed-AssocTy
464 // forall<Self, P1..Pn, Pn+1..Pm> {
465 // WellFormed((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
466 // :- Implemented(Self: Trait<P1..Pn>)
470 let trait_predicate = ty::TraitPredicate { trait_ref };
471 let hypothesis = tcx.mk_goal(
472 DomainGoal::Holds(WhereClause::Implemented(trait_predicate)).into_goal()
475 let wf_clause = ProgramClause {
476 goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)),
477 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
478 category: ProgramClauseCategory::WellFormed,
480 let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
482 // Rule Implied-Trait-From-AssocTy
484 // forall<Self, P1..Pn, Pn+1..Pm> {
485 // FromEnv(Self: Trait<P1..Pn>)
486 // :- FromEnv((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
490 let hypothesis = tcx.mk_goal(
491 DomainGoal::FromEnv(FromEnv::Ty(placeholder_ty)).into_goal()
494 let from_env_clause = ProgramClause {
495 goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)),
496 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
497 category: ProgramClauseCategory::ImpliedBound,
499 let from_env_clause = Clause::ForAll(ty::Binder::bind(from_env_clause));
501 // Rule ProjectionEq-Normalize
503 // ProjectionEq can succeed by normalizing:
505 // forall<Self, P1..Pn, Pn+1..Pm, U> {
506 // ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U) :-
507 // Normalize(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> U)
511 let offset = tcx.generics_of(trait_id).params
516 // Add a new type param after the existing ones (`U` in the comment above).
517 let ty_var = ty::Bound(
519 ty::BoundVar::from_u32(offset + 1).into()
522 // `ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U)`
523 let projection = ty::ProjectionPredicate {
525 ty: tcx.mk_ty(ty_var),
528 // `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> U)`
529 let hypothesis = tcx.mk_goal(
530 DomainGoal::Normalize(projection).into_goal()
533 // ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U) :-
534 // Normalize(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> U)
535 let normalize_clause = ProgramClause {
536 goal: DomainGoal::Holds(WhereClause::ProjectionEq(projection)),
537 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
538 category: ProgramClauseCategory::Other,
540 let normalize_clause = Clause::ForAll(ty::Binder::bind(normalize_clause));
542 let clauses = iter::once(projection_eq_clause)
543 .chain(iter::once(wf_clause))
544 .chain(iter::once(from_env_clause))
545 .chain(iter::once(normalize_clause));
547 tcx.mk_clauses(clauses)
550 pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
551 tcx: TyCtxt<'a, 'tcx, 'tcx>,
554 // Rule Normalize-From-Impl (see rustc guide)
557 // impl<P0..Pn> Trait<A1..An> for A0 {
558 // type AssocType<Pn+1..Pm> = T;
562 // FIXME: For the moment, we don't account for where clauses written on the associated
563 // ty definition (i.e. in the trait def, as in `type AssocType<T> where T: Sized`).
566 // forall<Pn+1..Pm> {
567 // Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
568 // Implemented(A0: Trait<A1..An>)
573 let item = tcx.associated_item(item_id);
574 debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
575 let impl_id = match item.container {
576 ty::AssociatedItemContainer::ImplContainer(impl_id) => impl_id,
577 _ => bug!("not an impl container"),
580 let impl_bound_vars = Substs::bound_vars_for_item(tcx, impl_id);
582 // `A0 as Trait<A1..An>`
583 let trait_ref = tcx.impl_trait_ref(impl_id)
585 .subst(tcx, impl_bound_vars);
588 let ty = tcx.type_of(item_id);
590 // `Implemented(A0: Trait<A1..An>)`
591 let trait_implemented: DomainGoal = ty::TraitPredicate { trait_ref }.lower();
593 // `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
594 let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
596 // `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
597 let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
599 // `Normalize(... -> T) :- ...`
600 let normalize_clause = ProgramClause {
601 goal: normalize_goal,
602 hypotheses: tcx.mk_goals(
603 iter::once(tcx.mk_goal(GoalKind::DomainGoal(trait_implemented)))
605 category: ProgramClauseCategory::Other,
607 let normalize_clause = Clause::ForAll(ty::Binder::bind(normalize_clause));
609 tcx.mk_clauses(iter::once(normalize_clause))
612 pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
613 if !tcx.features().rustc_attrs {
617 let mut visitor = ClauseDumper { tcx };
620 .visit_all_item_likes(&mut visitor.as_deep_visitor());
623 struct ClauseDumper<'a, 'tcx: 'a> {
624 tcx: TyCtxt<'a, 'tcx, 'tcx>,
627 impl<'a, 'tcx> ClauseDumper<'a, 'tcx> {
628 fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
629 let def_id = self.tcx.hir().local_def_id(node_id);
631 let mut clauses = None;
633 if attr.check_name("rustc_dump_program_clauses") {
634 clauses = Some(self.tcx.program_clauses_for(def_id));
637 if attr.check_name("rustc_dump_env_program_clauses") {
638 let environment = self.tcx.environment(def_id);
639 clauses = Some(self.tcx.program_clauses_for_env(*environment.skip_binder()));
642 if let Some(clauses) = clauses {
646 .struct_span_err(attr.span, "program clause dump");
648 let mut strings: Vec<_> = clauses
650 .map(|clause| clause.to_string())
655 for string in strings {
665 impl<'a, 'tcx> Visitor<'tcx> for ClauseDumper<'a, 'tcx> {
666 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
667 NestedVisitorMap::OnlyBodies(&self.tcx.hir())
670 fn visit_item(&mut self, item: &'tcx hir::Item) {
671 self.process_attrs(item.id, &item.attrs);
672 intravisit::walk_item(self, item);
675 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
676 self.process_attrs(trait_item.id, &trait_item.attrs);
677 intravisit::walk_trait_item(self, trait_item);
680 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
681 self.process_attrs(impl_item.id, &impl_item.attrs);
682 intravisit::walk_impl_item(self, impl_item);
685 fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
686 self.process_attrs(s.id, &s.attrs);
687 intravisit::walk_struct_field(self, s);