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}
;
35 crate fn provide(p
: &mut Providers
) {
38 program_clauses_for_env
: environment
::program_clauses_for_env
,
39 environment
: environment
::environment
,
44 crate trait Lower
<T
> {
45 /// Lower a rustc construct (e.g. `ty::TraitPredicate`) to a chalk-like type.
49 impl<T
, U
> Lower
<Vec
<U
>> for Vec
<T
>
53 fn lower(&self) -> Vec
<U
> {
54 self.iter().map(|item
| item
.lower()).collect()
58 impl<'tcx
> Lower
<WhereClause
<'tcx
>> for ty
::TraitPredicate
<'tcx
> {
59 fn lower(&self) -> WhereClause
<'tcx
> {
60 WhereClause
::Implemented(*self)
64 impl<'tcx
> Lower
<WhereClause
<'tcx
>> for ty
::ProjectionPredicate
<'tcx
> {
65 fn lower(&self) -> WhereClause
<'tcx
> {
66 WhereClause
::ProjectionEq(*self)
70 impl<'tcx
> Lower
<WhereClause
<'tcx
>> for ty
::RegionOutlivesPredicate
<'tcx
> {
71 fn lower(&self) -> WhereClause
<'tcx
> {
72 WhereClause
::RegionOutlives(*self)
76 impl<'tcx
> Lower
<WhereClause
<'tcx
>> for ty
::TypeOutlivesPredicate
<'tcx
> {
77 fn lower(&self) -> WhereClause
<'tcx
> {
78 WhereClause
::TypeOutlives(*self)
82 impl<'tcx
, T
> Lower
<DomainGoal
<'tcx
>> for T
84 T
: Lower
<WhereClause
<'tcx
>>,
86 fn lower(&self) -> DomainGoal
<'tcx
> {
87 DomainGoal
::Holds(self.lower())
91 /// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
92 /// lifetimes, e.g. `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
93 /// in that leaf-form (i.e. `Holds(Implemented(Binder<TraitPredicate>))` in the previous
94 /// example), we model them with quantified domain goals, e.g. as for the previous example:
95 /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
96 /// `Binder<Holds(Implemented(TraitPredicate))>`.
97 impl<'tcx
, T
> Lower
<PolyDomainGoal
<'tcx
>> for ty
::Binder
<T
>
99 T
: Lower
<DomainGoal
<'tcx
>> + ty
::fold
::TypeFoldable
<'tcx
>,
101 fn lower(&self) -> PolyDomainGoal
<'tcx
> {
102 self.map_bound_ref(|p
| p
.lower())
106 impl<'tcx
> Lower
<PolyDomainGoal
<'tcx
>> for ty
::Predicate
<'tcx
> {
107 fn lower(&self) -> PolyDomainGoal
<'tcx
> {
108 use rustc
::ty
::Predicate
;
111 Predicate
::Trait(predicate
) => predicate
.lower(),
112 Predicate
::RegionOutlives(predicate
) => predicate
.lower(),
113 Predicate
::TypeOutlives(predicate
) => predicate
.lower(),
114 Predicate
::Projection(predicate
) => predicate
.lower(),
115 Predicate
::WellFormed(ty
) => {
116 ty
::Binder
::dummy(DomainGoal
::WellFormed(WellFormed
::Ty(*ty
)))
118 Predicate
::ObjectSafe(..)
119 | Predicate
::ClosureKind(..)
120 | Predicate
::Subtype(..)
121 | Predicate
::ConstEvaluatable(..) => unimplemented
!(),
126 /// Used for implied bounds related rules (see rustc guide).
127 trait IntoFromEnvGoal
{
128 /// Transforms an existing goal into a `FromEnv` goal.
129 fn into_from_env_goal(self) -> Self;
132 /// Used for well-formedness related rules (see rustc guide).
133 trait IntoWellFormedGoal
{
134 /// Transforms an existing goal into a `WellFormed` goal.
135 fn into_well_formed_goal(self) -> Self;
138 impl<'tcx
> IntoFromEnvGoal
for DomainGoal
<'tcx
> {
139 fn into_from_env_goal(self) -> DomainGoal
<'tcx
> {
140 use self::WhereClause
::*;
143 DomainGoal
::Holds(Implemented(trait_ref
)) => {
144 DomainGoal
::FromEnv(FromEnv
::Trait(trait_ref
))
151 impl<'tcx
> IntoWellFormedGoal
for DomainGoal
<'tcx
> {
152 fn into_well_formed_goal(self) -> DomainGoal
<'tcx
> {
153 use self::WhereClause
::*;
156 DomainGoal
::Holds(Implemented(trait_ref
)) => {
157 DomainGoal
::WellFormed(WellFormed
::Trait(trait_ref
))
164 crate fn program_clauses_for
<'a
, 'tcx
>(
165 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
168 match tcx
.def_key(def_id
).disambiguated_data
.data
{
169 DefPathData
::Trait(_
) => program_clauses_for_trait(tcx
, def_id
),
170 DefPathData
::Impl
=> program_clauses_for_impl(tcx
, def_id
),
171 DefPathData
::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx
, def_id
),
172 DefPathData
::AssocTypeInTrait(..) => program_clauses_for_associated_type_def(tcx
, def_id
),
173 DefPathData
::TypeNs(..) => program_clauses_for_type_def(tcx
, def_id
),
178 fn program_clauses_for_trait
<'a
, 'tcx
>(
179 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
182 // `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
184 // Rule Implemented-From-Env (see rustc guide)
187 // forall<Self, P1..Pn> {
188 // Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
192 // `Self: Trait<P1..Pn>`
193 let trait_pred
= ty
::TraitPredicate
{
194 trait_ref
: ty
::TraitRef
::identity(tcx
, def_id
),
197 // `Implemented(Self: Trait<P1..Pn>)`
198 let impl_trait
: DomainGoal
= trait_pred
.lower();
200 // `FromEnv(Self: Trait<P1..Pn>)`
201 let from_env_goal
= tcx
.mk_goal(impl_trait
.into_from_env_goal().into_goal());
202 let hypotheses
= tcx
.intern_goals(&[from_env_goal
]);
204 // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
205 let implemented_from_env
= ProgramClause
{
208 category
: ProgramClauseCategory
::ImpliedBound
,
211 let clauses
= iter
::once(Clause
::ForAll(ty
::Binder
::dummy(implemented_from_env
)));
213 let where_clauses
= &tcx
.predicates_defined_on(def_id
).predicates
215 .map(|(wc
, _
)| wc
.lower())
216 .collect
::<Vec
<_
>>();
218 // Rule Implied-Bound-From-Trait
220 // For each where clause WC:
222 // forall<Self, P1..Pn> {
223 // FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn)
227 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
228 let implied_bound_clauses
= where_clauses
232 // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
233 .map(|wc
| wc
.map_bound(|goal
| ProgramClause
{
234 goal
: goal
.into_from_env_goal(),
236 category
: ProgramClauseCategory
::ImpliedBound
,
238 .map(Clause
::ForAll
);
240 // Rule WellFormed-TraitRef
242 // Here `WC` denotes the set of all where clauses:
244 // forall<Self, P1..Pn> {
245 // WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)
249 // `Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
250 let wf_conditions
= iter
::once(ty
::Binder
::dummy(trait_pred
.lower()))
254 .map(|wc
| wc
.map_bound(|goal
| goal
.into_well_formed_goal()))
257 // `WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
258 let wf_clause
= ProgramClause
{
259 goal
: DomainGoal
::WellFormed(WellFormed
::Trait(trait_pred
)),
260 hypotheses
: tcx
.mk_goals(
261 wf_conditions
.map(|wc
| tcx
.mk_goal(GoalKind
::from_poly_domain_goal(wc
, tcx
))),
263 category
: ProgramClauseCategory
::WellFormed
,
265 let wf_clause
= iter
::once(Clause
::ForAll(ty
::Binder
::dummy(wf_clause
)));
269 .chain(implied_bound_clauses
)
274 fn program_clauses_for_impl
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>, def_id
: DefId
) -> Clauses
<'tcx
> {
275 if let ImplPolarity
::Negative
= tcx
.impl_polarity(def_id
) {
276 return List
::empty();
279 // Rule Implemented-From-Impl (see rustc guide)
281 // `impl<P0..Pn> Trait<A1..An> for A0 where WC { .. }`
285 // Implemented(A0: Trait<A1..An>) :- WC
289 let trait_ref
= tcx
.impl_trait_ref(def_id
).expect("not an impl");
291 // `Implemented(A0: Trait<A1..An>)`
292 let trait_pred
= ty
::TraitPredicate { trait_ref }
.lower();
295 let where_clauses
= tcx
.predicates_of(def_id
).predicates
297 .map(|(wc
, _
)| wc
.lower());
299 // `Implemented(A0: Trait<A1..An>) :- WC`
300 let clause
= ProgramClause
{
302 hypotheses
: tcx
.mk_goals(
304 .map(|wc
| tcx
.mk_goal(GoalKind
::from_poly_domain_goal(wc
, tcx
))),
306 category
: ProgramClauseCategory
::Other
,
308 tcx
.mk_clauses(iter
::once(Clause
::ForAll(ty
::Binder
::dummy(clause
))))
311 pub fn program_clauses_for_type_def
<'a
, 'tcx
>(
312 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
315 // Rule WellFormed-Type
317 // `struct Ty<P1..Pn> where WC1, ..., WCm`
321 // WellFormed(Ty<...>) :- WC1, ..., WCm`
326 let ty
= tcx
.type_of(def_id
);
329 let where_clauses
= tcx
.predicates_of(def_id
).predicates
331 .map(|(wc
, _
)| wc
.lower())
332 .collect
::<Vec
<_
>>();
334 // `WellFormed(Ty<...>) :- WC1, ..., WCm`
335 let well_formed
= ProgramClause
{
336 goal
: DomainGoal
::WellFormed(WellFormed
::Ty(ty
)),
337 hypotheses
: tcx
.mk_goals(
341 .map(|wc
| tcx
.mk_goal(GoalKind
::from_poly_domain_goal(wc
, tcx
))),
343 category
: ProgramClauseCategory
::WellFormed
,
346 let well_formed_clause
= iter
::once(Clause
::ForAll(ty
::Binder
::dummy(well_formed
)));
350 // For each where clause `WC`:
353 // FromEnv(WC) :- FromEnv(Ty<...>)
357 // `FromEnv(Ty<...>)`
358 let from_env_goal
= tcx
.mk_goal(DomainGoal
::FromEnv(FromEnv
::Ty(ty
)).into_goal());
359 let hypotheses
= tcx
.intern_goals(&[from_env_goal
]);
361 // For each where clause `WC`:
362 let from_env_clauses
= where_clauses
365 // `FromEnv(WC) :- FromEnv(Ty<...>)`
366 .map(|wc
| wc
.map_bound(|goal
| ProgramClause
{
367 goal
: goal
.into_from_env_goal(),
369 category
: ProgramClauseCategory
::ImpliedBound
,
372 .map(Clause
::ForAll
);
374 tcx
.mk_clauses(well_formed_clause
.chain(from_env_clauses
))
377 pub fn program_clauses_for_associated_type_def
<'a
, 'tcx
>(
378 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
381 // Rule ProjectionEq-Skolemize
384 // trait Trait<P1..Pn> {
385 // type AssocType<Pn+1..Pm>;
389 // `ProjectionEq` can succeed by skolemizing, see "associated type"
392 // forall<Self, P1..Pn, Pn+1..Pm> {
394 // <Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> =
395 // (Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>
400 let item
= tcx
.associated_item(item_id
);
401 debug_assert_eq
!(item
.kind
, ty
::AssociatedKind
::Type
);
402 let trait_id
= match item
.container
{
403 ty
::AssociatedItemContainer
::TraitContainer(trait_id
) => trait_id
,
404 _
=> bug
!("not an trait container"),
406 let trait_ref
= ty
::TraitRef
::identity(tcx
, trait_id
);
408 let projection_ty
= ty
::ProjectionTy
::from_ref_and_name(tcx
, trait_ref
, item
.ident
);
409 let placeholder_ty
= tcx
.mk_ty(ty
::UnnormalizedProjection(projection_ty
));
410 let projection_eq
= WhereClause
::ProjectionEq(ty
::ProjectionPredicate
{
415 let projection_eq_clause
= ProgramClause
{
416 goal
: DomainGoal
::Holds(projection_eq
),
417 hypotheses
: ty
::List
::empty(),
418 category
: ProgramClauseCategory
::Other
,
421 // Rule WellFormed-AssocTy
423 // forall<Self, P1..Pn, Pn+1..Pm> {
424 // WellFormed((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
425 // :- Implemented(Self: Trait<P1..Pn>)
429 let trait_predicate
= ty
::TraitPredicate { trait_ref }
;
430 let hypothesis
= tcx
.mk_goal(
431 DomainGoal
::Holds(WhereClause
::Implemented(trait_predicate
)).into_goal()
433 let wf_clause
= ProgramClause
{
434 goal
: DomainGoal
::WellFormed(WellFormed
::Ty(placeholder_ty
)),
435 hypotheses
: tcx
.mk_goals(iter
::once(hypothesis
)),
436 category
: ProgramClauseCategory
::WellFormed
,
439 // Rule Implied-Trait-From-AssocTy
441 // forall<Self, P1..Pn, Pn+1..Pm> {
442 // FromEnv(Self: Trait<P1..Pn>)
443 // :- FromEnv((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
447 let hypothesis
= tcx
.mk_goal(
448 DomainGoal
::FromEnv(FromEnv
::Ty(placeholder_ty
)).into_goal()
450 let from_env_clause
= ProgramClause
{
451 goal
: DomainGoal
::FromEnv(FromEnv
::Trait(trait_predicate
)),
452 hypotheses
: tcx
.mk_goals(iter
::once(hypothesis
)),
453 category
: ProgramClauseCategory
::ImpliedBound
,
456 let clauses
= iter
::once(projection_eq_clause
)
457 .chain(iter
::once(wf_clause
))
458 .chain(iter
::once(from_env_clause
));
459 let clauses
= clauses
.map(|clause
| Clause
::ForAll(ty
::Binder
::dummy(clause
)));
460 tcx
.mk_clauses(clauses
)
463 pub fn program_clauses_for_associated_type_value
<'a
, 'tcx
>(
464 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
467 // Rule Normalize-From-Impl (see rustc guide)
470 // impl<P0..Pn> Trait<A1..An> for A0 {
471 // type AssocType<Pn+1..Pm> = T;
475 // FIXME: For the moment, we don't account for where clauses written on the associated
476 // ty definition (i.e. in the trait def, as in `type AssocType<T> where T: Sized`).
479 // forall<Pn+1..Pm> {
480 // Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
481 // Implemented(A0: Trait<A1..An>)
486 let item
= tcx
.associated_item(item_id
);
487 debug_assert_eq
!(item
.kind
, ty
::AssociatedKind
::Type
);
488 let impl_id
= match item
.container
{
489 ty
::AssociatedItemContainer
::ImplContainer(impl_id
) => impl_id
,
490 _
=> bug
!("not an impl container"),
493 // `A0 as Trait<A1..An>`
494 let trait_ref
= tcx
.impl_trait_ref(impl_id
).unwrap();
497 let ty
= tcx
.type_of(item_id
);
499 // `Implemented(A0: Trait<A1..An>)`
500 let trait_implemented
= ty
::Binder
::dummy(ty
::TraitPredicate { trait_ref }
.lower());
502 // `Implemented(A0: Trait<A1..An>)`
503 let hypotheses
= vec
![trait_implemented
];
505 // `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
506 let projection_ty
= ty
::ProjectionTy
::from_ref_and_name(tcx
, trait_ref
, item
.ident
);
508 // `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
509 let normalize_goal
= DomainGoal
::Normalize(ty
::ProjectionPredicate { projection_ty, ty }
);
511 // `Normalize(... -> T) :- ...`
512 let clause
= ProgramClause
{
513 goal
: normalize_goal
,
514 hypotheses
: tcx
.mk_goals(
517 .map(|wc
| tcx
.mk_goal(GoalKind
::from_poly_domain_goal(wc
, tcx
))),
519 category
: ProgramClauseCategory
::Other
,
521 tcx
.mk_clauses(iter
::once(Clause
::ForAll(ty
::Binder
::dummy(clause
))))
524 pub fn dump_program_clauses
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) {
525 if !tcx
.features().rustc_attrs
{
529 let mut visitor
= ClauseDumper { tcx }
;
532 .visit_all_item_likes(&mut visitor
.as_deep_visitor());
535 struct ClauseDumper
<'a
, 'tcx
: 'a
> {
536 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
539 impl<'a
, 'tcx
> ClauseDumper
<'a
, 'tcx
> {
540 fn process_attrs(&mut self, node_id
: ast
::NodeId
, attrs
: &[ast
::Attribute
]) {
541 let def_id
= self.tcx
.hir
.local_def_id(node_id
);
543 let mut clauses
= None
;
545 if attr
.check_name("rustc_dump_program_clauses") {
546 clauses
= Some(self.tcx
.program_clauses_for(def_id
));
549 if attr
.check_name("rustc_dump_env_program_clauses") {
550 let environment
= self.tcx
.environment(def_id
);
551 clauses
= Some(self.tcx
.program_clauses_for_env(environment
));
554 if let Some(clauses
) = clauses
{
558 .struct_span_err(attr
.span
, "program clause dump");
560 let mut strings
: Vec
<_
> = clauses
563 // Skip the top-level binder for a less verbose output
564 let program_clause
= match clause
{
565 Clause
::Implies(program_clause
) => program_clause
,
566 Clause
::ForAll(program_clause
) => program_clause
.skip_binder(),
568 program_clause
.to_string()
574 for string
in strings
{
584 impl<'a
, 'tcx
> Visitor
<'tcx
> for ClauseDumper
<'a
, 'tcx
> {
585 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'tcx
> {
586 NestedVisitorMap
::OnlyBodies(&self.tcx
.hir
)
589 fn visit_item(&mut self, item
: &'tcx hir
::Item
) {
590 self.process_attrs(item
.id
, &item
.attrs
);
591 intravisit
::walk_item(self, item
);
594 fn visit_trait_item(&mut self, trait_item
: &'tcx hir
::TraitItem
) {
595 self.process_attrs(trait_item
.id
, &trait_item
.attrs
);
596 intravisit
::walk_trait_item(self, trait_item
);
599 fn visit_impl_item(&mut self, impl_item
: &'tcx hir
::ImplItem
) {
600 self.process_attrs(impl_item
.id
, &impl_item
.attrs
);
601 intravisit
::walk_impl_item(self, impl_item
);
604 fn visit_struct_field(&mut self, s
: &'tcx hir
::StructField
) {
605 self.process_attrs(s
.id
, &s
.attrs
);
606 intravisit
::walk_struct_field(self, s
);