3 use rustc::hir::def::DefKind;
4 use rustc::hir::def_id::DefId;
5 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
6 use rustc::hir::map::definitions::DefPathData;
7 use rustc::hir::{self, ImplPolarity};
16 ProgramClauseCategory,
20 use rustc::ty::query::Providers;
21 use rustc::ty::{self, List, TyCtxt};
22 use rustc::ty::subst::{Subst, InternalSubsts};
24 use syntax::symbol::sym;
28 crate fn provide(p: &mut Providers<'_>) {
31 program_clauses_for_env: environment::program_clauses_for_env,
32 environment: environment::environment,
37 crate trait Lower<T> {
38 /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk-like type.
42 impl<T, U> Lower<Vec<U>> for Vec<T>
46 fn lower(&self) -> Vec<U> {
47 self.iter().map(|item| item.lower()).collect()
51 impl<'tcx> Lower<WhereClause<'tcx>> for ty::TraitPredicate<'tcx> {
52 fn lower(&self) -> WhereClause<'tcx> {
53 WhereClause::Implemented(*self)
57 impl<'tcx> Lower<WhereClause<'tcx>> for ty::ProjectionPredicate<'tcx> {
58 fn lower(&self) -> WhereClause<'tcx> {
59 WhereClause::ProjectionEq(*self)
63 impl<'tcx> Lower<WhereClause<'tcx>> for ty::RegionOutlivesPredicate<'tcx> {
64 fn lower(&self) -> WhereClause<'tcx> {
65 WhereClause::RegionOutlives(*self)
69 impl<'tcx> Lower<WhereClause<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
70 fn lower(&self) -> WhereClause<'tcx> {
71 WhereClause::TypeOutlives(*self)
75 impl<'tcx, T> Lower<DomainGoal<'tcx>> for T
77 T: Lower<WhereClause<'tcx>>,
79 fn lower(&self) -> DomainGoal<'tcx> {
80 DomainGoal::Holds(self.lower())
84 /// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
85 /// lifetimes, e.g., `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
86 /// in that leaf-form (i.e., `Holds(Implemented(Binder<TraitPredicate>))` in the previous
87 /// example), we model them with quantified domain goals, e.g., as for the previous example:
88 /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
89 /// `Binder<Holds(Implemented(TraitPredicate))>`.
90 impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
92 T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>,
94 fn lower(&self) -> PolyDomainGoal<'tcx> {
95 self.map_bound_ref(|p| p.lower())
99 impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
100 fn lower(&self) -> PolyDomainGoal<'tcx> {
101 use rustc::ty::Predicate;
104 Predicate::Trait(predicate) => predicate.lower(),
105 Predicate::RegionOutlives(predicate) => predicate.lower(),
106 Predicate::TypeOutlives(predicate) => predicate.lower(),
107 Predicate::Projection(predicate) => predicate.lower(),
109 Predicate::WellFormed(..) |
110 Predicate::ObjectSafe(..) |
111 Predicate::ClosureKind(..) |
112 Predicate::Subtype(..) |
113 Predicate::ConstEvaluatable(..) => {
114 bug!("unexpected predicate {}", self)
120 /// Used for implied bounds related rules (see rustc guide).
121 trait IntoFromEnvGoal {
122 /// Transforms an existing goal into a `FromEnv` goal.
123 fn into_from_env_goal(self) -> Self;
126 /// Used for well-formedness related rules (see rustc guide).
127 trait IntoWellFormedGoal {
128 /// Transforms an existing goal into a `WellFormed` goal.
129 fn into_well_formed_goal(self) -> Self;
132 impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
133 fn into_from_env_goal(self) -> DomainGoal<'tcx> {
134 use self::WhereClause::*;
137 DomainGoal::Holds(Implemented(trait_ref)) => {
138 DomainGoal::FromEnv(FromEnv::Trait(trait_ref))
145 impl<'tcx> IntoWellFormedGoal for DomainGoal<'tcx> {
146 fn into_well_formed_goal(self) -> DomainGoal<'tcx> {
147 use self::WhereClause::*;
150 DomainGoal::Holds(Implemented(trait_ref)) => {
151 DomainGoal::WellFormed(WellFormed::Trait(trait_ref))
158 crate fn program_clauses_for<'tcx>(
159 tcx: TyCtxt<'tcx, 'tcx>,
162 // FIXME(eddyb) this should only be using `def_kind`.
163 match tcx.def_key(def_id).disambiguated_data.data {
164 DefPathData::TypeNs(..) => match tcx.def_kind(def_id) {
166 | Some(DefKind::TraitAlias) => program_clauses_for_trait(tcx, def_id),
167 // FIXME(eddyb) deduplicate this `associated_item` call with
168 // `program_clauses_for_associated_type_{value,def}`.
169 Some(DefKind::AssocTy) => match tcx.associated_item(def_id).container {
170 ty::AssocItemContainer::ImplContainer(_) =>
171 program_clauses_for_associated_type_value(tcx, def_id),
172 ty::AssocItemContainer::TraitContainer(_) =>
173 program_clauses_for_associated_type_def(tcx, def_id)
175 Some(DefKind::Struct)
176 | Some(DefKind::Enum)
177 | Some(DefKind::TyAlias)
178 | Some(DefKind::Union)
179 | Some(DefKind::Existential) => program_clauses_for_type_def(tcx, def_id),
182 DefPathData::Impl => program_clauses_for_impl(tcx, def_id),
187 fn program_clauses_for_trait<'tcx>(
188 tcx: TyCtxt<'tcx, 'tcx>,
191 // `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
193 // Rule Implemented-From-Env (see rustc guide)
196 // forall<Self, P1..Pn> {
197 // Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
201 let bound_vars = InternalSubsts::bound_vars_for_item(tcx, def_id);
203 // `Self: Trait<P1..Pn>`
204 let trait_pred = ty::TraitPredicate {
205 trait_ref: ty::TraitRef {
211 // `Implemented(Self: Trait<P1..Pn>)`
212 let impl_trait: DomainGoal<'_> = trait_pred.lower();
214 // `FromEnv(Self: Trait<P1..Pn>)`
215 let from_env_goal = tcx.mk_goal(impl_trait.into_from_env_goal().into_goal());
216 let hypotheses = tcx.intern_goals(&[from_env_goal]);
218 // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
219 let implemented_from_env = ProgramClause {
222 category: ProgramClauseCategory::ImpliedBound,
225 let implemented_from_env = Clause::ForAll(ty::Binder::bind(implemented_from_env));
227 let predicates = &tcx.predicates_defined_on(def_id).predicates;
229 // Warning: these where clauses are not substituted for bound vars yet,
230 // so that we don't need to adjust binders in the `FromEnv` rules below
232 let where_clauses = &predicates
234 .map(|(wc, _)| wc.lower())
235 .collect::<Vec<_>>();
237 // Rule Implied-Bound-From-Trait
239 // For each where clause WC:
241 // forall<Self, P1..Pn> {
242 // FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn)
246 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
247 let implied_bound_clauses = where_clauses
251 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
253 // we move binders to the left
254 wc.map_bound(|goal| ProgramClause {
255 // FIXME: As where clauses can only bind lifetimes for now, and that named
256 // bound regions have a def-id, it is safe to just inject `bound_vars` and
257 // `hypotheses` (which contain named vars bound at index `0`) into this
258 // binding level. This may change if we ever allow where clauses to bind
259 // types (e.g. for GATs things), because bound types only use a `BoundVar`
260 // index (no def-id).
261 goal: goal.subst(tcx, bound_vars).into_from_env_goal(),
264 category: ProgramClauseCategory::ImpliedBound,
267 .map(Clause::ForAll);
269 // Rule WellFormed-TraitRef
271 // Here `WC` denotes the set of all where clauses:
273 // forall<Self, P1..Pn> {
274 // WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)
279 let wf_conditions = where_clauses
281 .map(|wc| wc.subst(tcx, bound_vars))
282 .map(|wc| wc.map_bound(|goal| goal.into_well_formed_goal()));
284 // `WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
285 let wf_clause = ProgramClause {
286 goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)),
287 hypotheses: tcx.mk_goals(
288 iter::once(tcx.mk_goal(GoalKind::DomainGoal(impl_trait))).chain(
289 wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx)))
292 category: ProgramClauseCategory::WellFormed,
294 let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
297 iter::once(implemented_from_env)
298 .chain(implied_bound_clauses)
299 .chain(iter::once(wf_clause))
303 fn program_clauses_for_impl(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> Clauses<'tcx> {
304 if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
305 return List::empty();
308 // Rule Implemented-From-Impl (see rustc guide)
310 // `impl<P0..Pn> Trait<A1..An> for A0 where WC { .. }`
314 // Implemented(A0: Trait<A1..An>) :- WC
318 let bound_vars = InternalSubsts::bound_vars_for_item(tcx, def_id);
320 let trait_ref = tcx.impl_trait_ref(def_id)
321 .expect("not an impl")
322 .subst(tcx, bound_vars);
324 // `Implemented(A0: Trait<A1..An>)`
325 let trait_pred = ty::TraitPredicate { trait_ref }.lower();
328 let predicates = &tcx.predicates_of(def_id).predicates;
329 let where_clauses = predicates
331 .map(|(wc, _)| wc.lower())
332 .map(|wc| wc.subst(tcx, bound_vars));
334 // `Implemented(A0: Trait<A1..An>) :- WC`
335 let clause = ProgramClause {
337 hypotheses: tcx.mk_goals(
339 .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
341 category: ProgramClauseCategory::Other,
343 tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::bind(clause))))
346 pub fn program_clauses_for_type_def<'tcx>(
347 tcx: TyCtxt<'tcx, 'tcx>,
350 // Rule WellFormed-Type
352 // `struct Ty<P1..Pn> where WC1, ..., WCm`
356 // WellFormed(Ty<...>) :- WellFormed(WC1), ..., WellFormed(WCm)`
360 let bound_vars = InternalSubsts::bound_vars_for_item(tcx, def_id);
363 let ty = tcx.type_of(def_id).subst(tcx, bound_vars);
365 // Warning: these where clauses are not substituted for bound vars yet,
366 // so that we don't need to adjust binders in the `FromEnv` rules below
368 let where_clauses = tcx.predicates_of(def_id).predicates
370 .map(|(wc, _)| wc.lower())
371 .collect::<Vec<_>>();
373 // `WellFormed(Ty<...>) :- WellFormed(WC1), ..., WellFormed(WCm)`
374 let well_formed_clause = ProgramClause {
375 goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
376 hypotheses: tcx.mk_goals(
379 .map(|wc| wc.subst(tcx, bound_vars))
380 .map(|wc| wc.map_bound(|bound| bound.into_well_formed_goal()))
381 .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
383 category: ProgramClauseCategory::WellFormed,
385 let well_formed_clause = Clause::ForAll(ty::Binder::bind(well_formed_clause));
387 // Rule Implied-Bound-From-Type
389 // For each where clause `WC`:
392 // FromEnv(WC) :- FromEnv(Ty<...>)
396 // `FromEnv(Ty<...>)`
397 let from_env_goal = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal());
398 let hypotheses = tcx.intern_goals(&[from_env_goal]);
400 // For each where clause `WC`:
401 let from_env_clauses = where_clauses
404 // `FromEnv(WC) :- FromEnv(Ty<...>)`
406 // move the binders to the left
407 wc.map_bound(|goal| ProgramClause {
408 // FIXME: we inject `bound_vars` and `hypotheses` into this binding
409 // level, which may be incorrect in the future: see the FIXME in
410 // `program_clauses_for_trait`.
411 goal: goal.subst(tcx, bound_vars).into_from_env_goal(),
414 category: ProgramClauseCategory::ImpliedBound,
418 .map(Clause::ForAll);
420 tcx.mk_clauses(iter::once(well_formed_clause).chain(from_env_clauses))
423 pub fn program_clauses_for_associated_type_def<'tcx>(
424 tcx: TyCtxt<'tcx, 'tcx>,
427 // Rule ProjectionEq-Placeholder
430 // trait Trait<P1..Pn> {
431 // type AssocType<Pn+1..Pm>;
435 // `ProjectionEq` can succeed by skolemizing, see "associated type"
438 // forall<Self, P1..Pn, Pn+1..Pm> {
440 // <Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> =
441 // (Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>
446 let item = tcx.associated_item(item_id);
447 debug_assert_eq!(item.kind, ty::AssocKind::Type);
448 let trait_id = match item.container {
449 ty::AssocItemContainer::TraitContainer(trait_id) => trait_id,
450 _ => bug!("not an trait container"),
453 let trait_bound_vars = InternalSubsts::bound_vars_for_item(tcx, trait_id);
454 let trait_ref = ty::TraitRef {
456 substs: trait_bound_vars,
459 let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
460 let placeholder_ty = tcx.mk_ty(ty::UnnormalizedProjection(projection_ty));
461 let projection_eq = WhereClause::ProjectionEq(ty::ProjectionPredicate {
466 let projection_eq_clause = ProgramClause {
467 goal: DomainGoal::Holds(projection_eq),
468 hypotheses: ty::List::empty(),
469 category: ProgramClauseCategory::Other,
471 let projection_eq_clause = Clause::ForAll(ty::Binder::bind(projection_eq_clause));
473 // Rule WellFormed-AssocTy
475 // forall<Self, P1..Pn, Pn+1..Pm> {
476 // WellFormed((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
477 // :- WellFormed(Self: Trait<P1..Pn>)
481 let trait_predicate = ty::TraitPredicate { trait_ref };
482 let hypothesis = tcx.mk_goal(
483 DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)).into_goal()
486 let wf_clause = ProgramClause {
487 goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)),
488 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
489 category: ProgramClauseCategory::WellFormed,
491 let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
493 // Rule Implied-Trait-From-AssocTy
495 // forall<Self, P1..Pn, Pn+1..Pm> {
496 // FromEnv(Self: Trait<P1..Pn>)
497 // :- FromEnv((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
501 let hypothesis = tcx.mk_goal(
502 DomainGoal::FromEnv(FromEnv::Ty(placeholder_ty)).into_goal()
505 let from_env_clause = ProgramClause {
506 goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)),
507 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
508 category: ProgramClauseCategory::ImpliedBound,
510 let from_env_clause = Clause::ForAll(ty::Binder::bind(from_env_clause));
512 // Rule ProjectionEq-Normalize
514 // ProjectionEq can succeed by normalizing:
516 // forall<Self, P1..Pn, Pn+1..Pm, U> {
517 // ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U) :-
518 // Normalize(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> U)
522 let offset = tcx.generics_of(trait_id).params
527 // Add a new type param after the existing ones (`U` in the comment above).
528 let ty_var = ty::Bound(
530 ty::BoundVar::from_u32(offset + 1).into()
533 // `ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U)`
534 let projection = ty::ProjectionPredicate {
536 ty: tcx.mk_ty(ty_var),
539 // `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> U)`
540 let hypothesis = tcx.mk_goal(
541 DomainGoal::Normalize(projection).into_goal()
544 // ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U) :-
545 // Normalize(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> U)
546 let normalize_clause = ProgramClause {
547 goal: DomainGoal::Holds(WhereClause::ProjectionEq(projection)),
548 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
549 category: ProgramClauseCategory::Other,
551 let normalize_clause = Clause::ForAll(ty::Binder::bind(normalize_clause));
553 let clauses = iter::once(projection_eq_clause)
554 .chain(iter::once(wf_clause))
555 .chain(iter::once(from_env_clause))
556 .chain(iter::once(normalize_clause));
558 tcx.mk_clauses(clauses)
561 pub fn program_clauses_for_associated_type_value<'tcx>(
562 tcx: TyCtxt<'tcx, 'tcx>,
565 // Rule Normalize-From-Impl (see rustc guide)
568 // impl<P0..Pn> Trait<A1..An> for A0 {
569 // type AssocType<Pn+1..Pm> = T;
573 // FIXME: For the moment, we don't account for where clauses written on the associated
574 // ty definition (i.e., in the trait def, as in `type AssocType<T> where T: Sized`).
577 // forall<Pn+1..Pm> {
578 // Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
579 // Implemented(A0: Trait<A1..An>)
584 let item = tcx.associated_item(item_id);
585 debug_assert_eq!(item.kind, ty::AssocKind::Type);
586 let impl_id = match item.container {
587 ty::AssocItemContainer::ImplContainer(impl_id) => impl_id,
588 _ => bug!("not an impl container"),
591 let impl_bound_vars = InternalSubsts::bound_vars_for_item(tcx, impl_id);
593 // `A0 as Trait<A1..An>`
594 let trait_ref = tcx.impl_trait_ref(impl_id)
596 .subst(tcx, impl_bound_vars);
599 let ty = tcx.type_of(item_id);
601 // `Implemented(A0: Trait<A1..An>)`
602 let trait_implemented: DomainGoal<'_> = ty::TraitPredicate { trait_ref }.lower();
604 // `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
605 let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
607 // `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
608 let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
610 // `Normalize(... -> T) :- ...`
611 let normalize_clause = ProgramClause {
612 goal: normalize_goal,
613 hypotheses: tcx.mk_goals(
614 iter::once(tcx.mk_goal(GoalKind::DomainGoal(trait_implemented)))
616 category: ProgramClauseCategory::Other,
618 let normalize_clause = Clause::ForAll(ty::Binder::bind(normalize_clause));
620 tcx.mk_clauses(iter::once(normalize_clause))
623 pub fn dump_program_clauses<'tcx>(tcx: TyCtxt<'tcx, 'tcx>) {
624 if !tcx.features().rustc_attrs {
628 let mut visitor = ClauseDumper { tcx };
631 .visit_all_item_likes(&mut visitor.as_deep_visitor());
634 struct ClauseDumper<'tcx> {
635 tcx: TyCtxt<'tcx, 'tcx>,
638 impl ClauseDumper<'tcx> {
639 fn process_attrs(&mut self, hir_id: hir::HirId, attrs: &[ast::Attribute]) {
640 let def_id = self.tcx.hir().local_def_id_from_hir_id(hir_id);
642 let mut clauses = None;
644 if attr.check_name(sym::rustc_dump_program_clauses) {
645 clauses = Some(self.tcx.program_clauses_for(def_id));
648 if attr.check_name(sym::rustc_dump_env_program_clauses) {
649 let environment = self.tcx.environment(def_id);
650 clauses = Some(self.tcx.program_clauses_for_env(environment));
653 if let Some(clauses) = clauses {
657 .struct_span_err(attr.span, "program clause dump");
659 let mut strings: Vec<_> = clauses
661 .map(|clause| clause.to_string())
666 for string in strings {
676 impl Visitor<'tcx> for ClauseDumper<'tcx> {
677 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
678 NestedVisitorMap::OnlyBodies(&self.tcx.hir())
681 fn visit_item(&mut self, item: &'tcx hir::Item) {
682 self.process_attrs(item.hir_id, &item.attrs);
683 intravisit::walk_item(self, item);
686 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
687 self.process_attrs(trait_item.hir_id, &trait_item.attrs);
688 intravisit::walk_trait_item(self, trait_item);
691 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
692 self.process_attrs(impl_item.hir_id, &impl_item.attrs);
693 intravisit::walk_impl_item(self, impl_item);
696 fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
697 self.process_attrs(s.hir_id, &s.attrs);
698 intravisit::walk_struct_field(self, s);