3 use rustc::hir::map::definitions::DefPathData;
4 use rustc::hir::map::Map;
6 Clause, Clauses, DomainGoal, FromEnv, GoalKind, PolyDomainGoal, ProgramClause,
7 ProgramClauseCategory, WellFormed, WhereClause,
9 use rustc::ty::query::Providers;
10 use rustc::ty::subst::{InternalSubsts, Subst};
11 use rustc::ty::{self, List, TyCtxt};
13 use rustc_hir::def::DefKind;
14 use rustc_hir::def_id::DefId;
15 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
16 use rustc_span::symbol::sym;
21 crate fn provide(p: &mut Providers<'_>) {
24 program_clauses_for_env: environment::program_clauses_for_env,
25 environment: environment::environment,
30 crate trait Lower<T> {
31 /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk-like type.
35 impl<T, U> Lower<Vec<U>> for Vec<T>
39 fn lower(&self) -> Vec<U> {
40 self.iter().map(|item| item.lower()).collect()
44 impl<'tcx> Lower<WhereClause<'tcx>> for ty::TraitPredicate<'tcx> {
45 fn lower(&self) -> WhereClause<'tcx> {
46 WhereClause::Implemented(*self)
50 impl<'tcx> Lower<WhereClause<'tcx>> for ty::ProjectionPredicate<'tcx> {
51 fn lower(&self) -> WhereClause<'tcx> {
52 WhereClause::ProjectionEq(*self)
56 impl<'tcx> Lower<WhereClause<'tcx>> for ty::RegionOutlivesPredicate<'tcx> {
57 fn lower(&self) -> WhereClause<'tcx> {
58 WhereClause::RegionOutlives(*self)
62 impl<'tcx> Lower<WhereClause<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
63 fn lower(&self) -> WhereClause<'tcx> {
64 WhereClause::TypeOutlives(*self)
68 impl<'tcx, T> Lower<DomainGoal<'tcx>> for T
70 T: Lower<WhereClause<'tcx>>,
72 fn lower(&self) -> DomainGoal<'tcx> {
73 DomainGoal::Holds(self.lower())
77 /// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
78 /// lifetimes, e.g., `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
79 /// in that leaf-form (i.e., `Holds(Implemented(Binder<TraitPredicate>))` in the previous
80 /// example), we model them with quantified domain goals, e.g., as for the previous example:
81 /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
82 /// `Binder<Holds(Implemented(TraitPredicate))>`.
83 impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
85 T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>,
87 fn lower(&self) -> PolyDomainGoal<'tcx> {
88 self.map_bound_ref(|p| p.lower())
92 impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
93 fn lower(&self) -> PolyDomainGoal<'tcx> {
94 use rustc::ty::Predicate;
97 Predicate::Trait(predicate, _) => predicate.lower(),
98 Predicate::RegionOutlives(predicate) => predicate.lower(),
99 Predicate::TypeOutlives(predicate) => predicate.lower(),
100 Predicate::Projection(predicate) => predicate.lower(),
102 Predicate::WellFormed(..)
103 | Predicate::ObjectSafe(..)
104 | Predicate::ClosureKind(..)
105 | Predicate::Subtype(..)
106 | Predicate::ConstEvaluatable(..) => bug!("unexpected predicate {}", self),
111 /// Used for implied bounds related rules (see rustc guide).
112 trait IntoFromEnvGoal {
113 /// Transforms an existing goal into a `FromEnv` goal.
114 fn into_from_env_goal(self) -> Self;
117 /// Used for well-formedness related rules (see rustc guide).
118 trait IntoWellFormedGoal {
119 /// Transforms an existing goal into a `WellFormed` goal.
120 fn into_well_formed_goal(self) -> Self;
123 impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
124 fn into_from_env_goal(self) -> DomainGoal<'tcx> {
125 use self::WhereClause::*;
128 DomainGoal::Holds(Implemented(trait_ref)) => {
129 DomainGoal::FromEnv(FromEnv::Trait(trait_ref))
136 impl<'tcx> IntoWellFormedGoal for DomainGoal<'tcx> {
137 fn into_well_formed_goal(self) -> DomainGoal<'tcx> {
138 use self::WhereClause::*;
141 DomainGoal::Holds(Implemented(trait_ref)) => {
142 DomainGoal::WellFormed(WellFormed::Trait(trait_ref))
149 crate fn program_clauses_for(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> {
150 // FIXME(eddyb) this should only be using `def_kind`.
151 match tcx.def_key(def_id).disambiguated_data.data {
152 DefPathData::TypeNs(..) => match tcx.def_kind(def_id) {
153 Some(DefKind::Trait) | Some(DefKind::TraitAlias) => {
154 program_clauses_for_trait(tcx, def_id)
156 // FIXME(eddyb) deduplicate this `associated_item` call with
157 // `program_clauses_for_associated_type_{value,def}`.
158 Some(DefKind::AssocTy) => match tcx.associated_item(def_id).container {
159 ty::AssocItemContainer::ImplContainer(_) => {
160 program_clauses_for_associated_type_value(tcx, def_id)
162 ty::AssocItemContainer::TraitContainer(_) => {
163 program_clauses_for_associated_type_def(tcx, def_id)
166 Some(DefKind::Struct)
167 | Some(DefKind::Enum)
168 | Some(DefKind::TyAlias)
169 | Some(DefKind::Union)
170 | Some(DefKind::OpaqueTy) => program_clauses_for_type_def(tcx, def_id),
173 DefPathData::Impl => program_clauses_for_impl(tcx, def_id),
178 fn program_clauses_for_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> {
179 // `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
181 // Rule Implemented-From-Env (see rustc guide)
184 // forall<Self, P1..Pn> {
185 // Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
189 let bound_vars = InternalSubsts::bound_vars_for_item(tcx, def_id);
191 // `Self: Trait<P1..Pn>`
192 let trait_pred = ty::TraitPredicate { trait_ref: ty::TraitRef { def_id, substs: bound_vars } };
194 // `Implemented(Self: Trait<P1..Pn>)`
195 let impl_trait: DomainGoal<'_> = trait_pred.lower();
197 // `FromEnv(Self: Trait<P1..Pn>)`
198 let from_env_goal = tcx.mk_goal(impl_trait.into_from_env_goal().into_goal());
199 let hypotheses = tcx.intern_goals(&[from_env_goal]);
201 // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
202 let implemented_from_env = ProgramClause {
205 category: ProgramClauseCategory::ImpliedBound,
208 let implemented_from_env = Clause::ForAll(ty::Binder::bind(implemented_from_env));
210 let predicates = tcx.predicates_defined_on(def_id).predicates;
212 // Warning: these where clauses are not substituted for bound vars yet,
213 // so that we don't need to adjust binders in the `FromEnv` rules below
215 let where_clauses = &predicates.iter().map(|(wc, _)| wc.lower()).collect::<Vec<_>>();
217 // Rule Implied-Bound-From-Trait
219 // For each where clause WC:
221 // forall<Self, P1..Pn> {
222 // FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn)
226 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
227 let implied_bound_clauses = where_clauses
230 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
232 // we move binders to the left
233 wc.map_bound(|goal| ProgramClause {
234 // FIXME: As where clauses can only bind lifetimes for now, and that named
235 // bound regions have a def-id, it is safe to just inject `bound_vars` and
236 // `hypotheses` (which contain named vars bound at index `0`) into this
237 // binding level. This may change if we ever allow where clauses to bind
238 // types (e.g. for GATs things), because bound types only use a `BoundVar`
239 // index (no def-id).
240 goal: goal.subst(tcx, bound_vars).into_from_env_goal(),
243 category: ProgramClauseCategory::ImpliedBound,
246 .map(Clause::ForAll);
248 // Rule WellFormed-TraitRef
250 // Here `WC` denotes the set of all where clauses:
252 // forall<Self, P1..Pn> {
253 // WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)
258 let wf_conditions = where_clauses
260 .map(|wc| wc.subst(tcx, bound_vars))
261 .map(|wc| wc.map_bound(|goal| goal.into_well_formed_goal()));
263 // `WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
264 let wf_clause = ProgramClause {
265 goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)),
266 hypotheses: tcx.mk_goals(
267 iter::once(tcx.mk_goal(GoalKind::DomainGoal(impl_trait))).chain(
268 wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
271 category: ProgramClauseCategory::WellFormed,
273 let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
276 iter::once(implemented_from_env).chain(implied_bound_clauses).chain(iter::once(wf_clause)),
280 fn program_clauses_for_impl(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> {
281 if let ty::ImplPolarity::Negative = tcx.impl_polarity(def_id) {
282 return List::empty();
285 // Rule Implemented-From-Impl (see rustc guide)
287 // `impl<P0..Pn> Trait<A1..An> for A0 where WC { .. }`
291 // Implemented(A0: Trait<A1..An>) :- WC
295 let bound_vars = InternalSubsts::bound_vars_for_item(tcx, def_id);
297 let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl").subst(tcx, bound_vars);
299 // `Implemented(A0: Trait<A1..An>)`
300 let trait_pred = ty::TraitPredicate { trait_ref }.lower();
303 let predicates = tcx.predicates_of(def_id).predicates;
305 predicates.iter().map(|(wc, _)| wc.lower()).map(|wc| wc.subst(tcx, bound_vars));
307 // `Implemented(A0: Trait<A1..An>) :- WC`
308 let clause = ProgramClause {
310 hypotheses: tcx.mk_goals(
311 where_clauses.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
313 category: ProgramClauseCategory::Other,
315 tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::bind(clause))))
318 pub fn program_clauses_for_type_def(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> {
319 // Rule WellFormed-Type
321 // `struct Ty<P1..Pn> where WC1, ..., WCm`
325 // WellFormed(Ty<...>) :- WellFormed(WC1), ..., WellFormed(WCm)`
329 let bound_vars = InternalSubsts::bound_vars_for_item(tcx, def_id);
332 let ty = tcx.type_of(def_id).subst(tcx, bound_vars);
334 // Warning: these where clauses are not substituted for bound vars yet,
335 // so that we don't need to adjust binders in the `FromEnv` rules below
338 tcx.predicates_of(def_id).predicates.iter().map(|(wc, _)| wc.lower()).collect::<Vec<_>>();
340 // `WellFormed(Ty<...>) :- WellFormed(WC1), ..., WellFormed(WCm)`
341 let well_formed_clause = ProgramClause {
342 goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
343 hypotheses: tcx.mk_goals(
346 .map(|wc| wc.subst(tcx, bound_vars))
347 .map(|wc| wc.map_bound(|bound| bound.into_well_formed_goal()))
348 .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
350 category: ProgramClauseCategory::WellFormed,
352 let well_formed_clause = Clause::ForAll(ty::Binder::bind(well_formed_clause));
354 // Rule Implied-Bound-From-Type
356 // For each where clause `WC`:
359 // FromEnv(WC) :- FromEnv(Ty<...>)
363 // `FromEnv(Ty<...>)`
364 let from_env_goal = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal());
365 let hypotheses = tcx.intern_goals(&[from_env_goal]);
367 // For each where clause `WC`:
368 let from_env_clauses = where_clauses
370 // `FromEnv(WC) :- FromEnv(Ty<...>)`
372 // move the binders to the left
373 wc.map_bound(|goal| ProgramClause {
374 // FIXME: we inject `bound_vars` and `hypotheses` into this binding
375 // level, which may be incorrect in the future: see the FIXME in
376 // `program_clauses_for_trait`.
377 goal: goal.subst(tcx, bound_vars).into_from_env_goal(),
380 category: ProgramClauseCategory::ImpliedBound,
383 .map(Clause::ForAll);
385 tcx.mk_clauses(iter::once(well_formed_clause).chain(from_env_clauses))
388 pub fn program_clauses_for_associated_type_def(tcx: TyCtxt<'_>, item_id: DefId) -> Clauses<'_> {
389 // Rule ProjectionEq-Placeholder
392 // trait Trait<P1..Pn> {
393 // type AssocType<Pn+1..Pm>;
397 // `ProjectionEq` can succeed by skolemizing, see "associated type"
400 // forall<Self, P1..Pn, Pn+1..Pm> {
402 // <Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> =
403 // (Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>
408 let item = tcx.associated_item(item_id);
409 debug_assert_eq!(item.kind, ty::AssocKind::Type);
410 let trait_id = match item.container {
411 ty::AssocItemContainer::TraitContainer(trait_id) => trait_id,
412 _ => bug!("not an trait container"),
415 let trait_bound_vars = InternalSubsts::bound_vars_for_item(tcx, trait_id);
416 let trait_ref = ty::TraitRef { def_id: trait_id, substs: trait_bound_vars };
418 let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
419 let placeholder_ty = tcx.mk_ty(ty::UnnormalizedProjection(projection_ty));
421 WhereClause::ProjectionEq(ty::ProjectionPredicate { projection_ty, ty: placeholder_ty });
423 let projection_eq_clause = ProgramClause {
424 goal: DomainGoal::Holds(projection_eq),
425 hypotheses: ty::List::empty(),
426 category: ProgramClauseCategory::Other,
428 let projection_eq_clause = Clause::ForAll(ty::Binder::bind(projection_eq_clause));
430 // Rule WellFormed-AssocTy
432 // forall<Self, P1..Pn, Pn+1..Pm> {
433 // WellFormed((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
434 // :- WellFormed(Self: Trait<P1..Pn>)
438 let trait_predicate = ty::TraitPredicate { trait_ref };
440 tcx.mk_goal(DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)).into_goal());
442 let wf_clause = ProgramClause {
443 goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)),
444 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
445 category: ProgramClauseCategory::WellFormed,
447 let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
449 // Rule Implied-Trait-From-AssocTy
451 // forall<Self, P1..Pn, Pn+1..Pm> {
452 // FromEnv(Self: Trait<P1..Pn>)
453 // :- FromEnv((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
457 let hypothesis = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(placeholder_ty)).into_goal());
459 let from_env_clause = ProgramClause {
460 goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)),
461 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
462 category: ProgramClauseCategory::ImpliedBound,
464 let from_env_clause = Clause::ForAll(ty::Binder::bind(from_env_clause));
466 // Rule ProjectionEq-Normalize
468 // ProjectionEq can succeed by normalizing:
470 // forall<Self, P1..Pn, Pn+1..Pm, U> {
471 // ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U) :-
472 // Normalize(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> U)
476 let offset = tcx.generics_of(trait_id).params.iter().map(|p| p.index).max().unwrap_or(0);
477 // Add a new type param after the existing ones (`U` in the comment above).
478 let ty_var = ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(offset + 1).into());
480 // `ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U)`
481 let projection = ty::ProjectionPredicate { projection_ty, ty: tcx.mk_ty(ty_var) };
483 // `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> U)`
484 let hypothesis = tcx.mk_goal(DomainGoal::Normalize(projection).into_goal());
486 // ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U) :-
487 // Normalize(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> U)
488 let normalize_clause = ProgramClause {
489 goal: DomainGoal::Holds(WhereClause::ProjectionEq(projection)),
490 hypotheses: tcx.mk_goals(iter::once(hypothesis)),
491 category: ProgramClauseCategory::Other,
493 let normalize_clause = Clause::ForAll(ty::Binder::bind(normalize_clause));
495 let clauses = iter::once(projection_eq_clause)
496 .chain(iter::once(wf_clause))
497 .chain(iter::once(from_env_clause))
498 .chain(iter::once(normalize_clause));
500 tcx.mk_clauses(clauses)
503 pub fn program_clauses_for_associated_type_value(tcx: TyCtxt<'_>, item_id: DefId) -> Clauses<'_> {
504 // Rule Normalize-From-Impl (see rustc guide)
507 // impl<P0..Pn> Trait<A1..An> for A0 {
508 // type AssocType<Pn+1..Pm> = T;
512 // FIXME: For the moment, we don't account for where clauses written on the associated
513 // ty definition (i.e., in the trait def, as in `type AssocType<T> where T: Sized`).
516 // forall<Pn+1..Pm> {
517 // Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
518 // Implemented(A0: Trait<A1..An>)
523 let item = tcx.associated_item(item_id);
524 debug_assert_eq!(item.kind, ty::AssocKind::Type);
525 let impl_id = match item.container {
526 ty::AssocItemContainer::ImplContainer(impl_id) => impl_id,
527 _ => bug!("not an impl container"),
530 let impl_bound_vars = InternalSubsts::bound_vars_for_item(tcx, impl_id);
532 // `A0 as Trait<A1..An>`
533 let trait_ref = tcx.impl_trait_ref(impl_id).unwrap().subst(tcx, impl_bound_vars);
536 let ty = tcx.type_of(item_id);
538 // `Implemented(A0: Trait<A1..An>)`
539 let trait_implemented: DomainGoal<'_> = ty::TraitPredicate { trait_ref }.lower();
541 // `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
542 let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
544 // `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
545 let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
547 // `Normalize(... -> T) :- ...`
548 let normalize_clause = ProgramClause {
549 goal: normalize_goal,
550 hypotheses: tcx.mk_goals(iter::once(tcx.mk_goal(GoalKind::DomainGoal(trait_implemented)))),
551 category: ProgramClauseCategory::Other,
553 let normalize_clause = Clause::ForAll(ty::Binder::bind(normalize_clause));
555 tcx.mk_clauses(iter::once(normalize_clause))
558 pub fn dump_program_clauses(tcx: TyCtxt<'_>) {
559 if !tcx.features().rustc_attrs {
563 let mut visitor = ClauseDumper { tcx };
564 tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
567 struct ClauseDumper<'tcx> {
571 impl ClauseDumper<'tcx> {
572 fn process_attrs(&mut self, hir_id: hir::HirId, attrs: &[ast::Attribute]) {
573 let def_id = self.tcx.hir().local_def_id(hir_id);
575 let mut clauses = None;
577 if attr.check_name(sym::rustc_dump_program_clauses) {
578 clauses = Some(self.tcx.program_clauses_for(def_id));
581 if attr.check_name(sym::rustc_dump_env_program_clauses) {
582 let environment = self.tcx.environment(def_id);
583 clauses = Some(self.tcx.program_clauses_for_env(environment));
586 if let Some(clauses) = clauses {
587 let mut err = self.tcx.sess.struct_span_err(attr.span, "program clause dump");
589 let mut strings: Vec<_> = clauses.iter().map(|clause| clause.to_string()).collect();
593 for string in strings {
603 impl Visitor<'tcx> for ClauseDumper<'tcx> {
604 type Map = Map<'tcx>;
606 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> {
607 NestedVisitorMap::OnlyBodies(&self.tcx.hir())
610 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
611 self.process_attrs(item.hir_id, &item.attrs);
612 intravisit::walk_item(self, item);
615 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
616 self.process_attrs(trait_item.hir_id, &trait_item.attrs);
617 intravisit::walk_trait_item(self, trait_item);
620 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
621 self.process_attrs(impl_item.hir_id, &impl_item.attrs);
622 intravisit::walk_impl_item(self, impl_item);
625 fn visit_struct_field(&mut self, s: &'tcx hir::StructField<'tcx>) {
626 self.process_attrs(s.hir_id, &s.attrs);
627 intravisit::walk_struct_field(self, s);