Skip to content

Commit

Permalink
Auto merge of #49626 - fanzier:chalk-lowering, r=scalexm
Browse files Browse the repository at this point in the history
Implement Chalk lowering rule Normalize-From-Impl

This extends the Chalk lowering pass with the "Normalize-From-Impl" rule for generating program clauses from a trait definition as part of #49177.

r? @nikomatsakis
  • Loading branch information
bors committed Apr 17, 2018
2 parents 8728c7a + b7c4a57 commit d703622
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::DomainGoal<'tcx>
FromEnv(where_clause) => where_clause.hash_stable(hcx, hasher),

WellFormedTy(ty) => ty.hash_stable(hcx, hasher),
Normalize(projection) => projection.hash_stable(hcx, hasher),
FromEnvTy(ty) => ty.hash_stable(hcx, hasher),
RegionOutlives(predicate) => predicate.hash_stable(hcx, hasher),
TypeOutlives(predicate) => predicate.hash_stable(hcx, hasher),
Expand Down
1 change: 1 addition & 0 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ pub enum DomainGoal<'tcx> {
WellFormed(WhereClauseAtom<'tcx>),
FromEnv(WhereClauseAtom<'tcx>),
WellFormedTy(Ty<'tcx>),
Normalize(ty::ProjectionPredicate<'tcx>),
FromEnvTy(Ty<'tcx>),
RegionOutlives(ty::RegionOutlivesPredicate<'tcx>),
TypeOutlives(ty::TypeOutlivesPredicate<'tcx>),
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> {
FromEnv(Implemented(trait_ref)) => write!(fmt, "FromEnv({})", trait_ref),
FromEnv(ProjectionEq(projection)) => write!(fmt, "FromEnv({})", projection),
WellFormedTy(ty) => write!(fmt, "WellFormed({})", ty),
Normalize(projection) => write!(fmt, "Normalize({})", projection),
FromEnvTy(ty) => write!(fmt, "FromEnv({})", ty),
RegionOutlives(predicate) => write!(fmt, "RegionOutlives({})", predicate),
TypeOutlives(predicate) => write!(fmt, "TypeOutlives({})", predicate),
Expand Down Expand Up @@ -538,6 +539,7 @@ EnumTypeFoldableImpl! {
(traits::DomainGoal::WellFormed)(wc),
(traits::DomainGoal::FromEnv)(wc),
(traits::DomainGoal::WellFormedTy)(ty),
(traits::DomainGoal::Normalize)(projection),
(traits::DomainGoal::FromEnvTy)(ty),
(traits::DomainGoal::RegionOutlives)(predicate),
(traits::DomainGoal::TypeOutlives)(predicate),
Expand Down
71 changes: 67 additions & 4 deletions src/librustc_traits/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
FromEnv(..) |
WellFormedTy(..) |
FromEnvTy(..) |
Normalize(..) |
RegionOutlives(..) |
TypeOutlives(..) => self,
}
Expand All @@ -118,10 +119,20 @@ crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
-> Lrc<&'tcx Slice<Clause<'tcx>>>
{
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let item = tcx.hir.expect_item(node_id);
match item.node {
hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
let node = tcx.hir.find(node_id).unwrap();
match node {
hir::map::Node::NodeItem(item) => match item.node {
hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
_ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
}
hir::map::Node::NodeImplItem(item) => {
if let hir::ImplItemKind::Type(..) = item.node {
program_clauses_for_associated_type_value(tcx, def_id)
} else {
Lrc::new(tcx.mk_clauses(iter::empty::<Clause>()))
}
},

// FIXME: other constructions e.g. traits, associated types...
_ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
Expand Down Expand Up @@ -233,6 +244,58 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId
Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))))
}

pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
item_id: DefId,
) -> Lrc<&'tcx Slice<Clause<'tcx>>> {
// Rule Normalize-From-Impl (see rustc guide)
//
// ```impl<P0..Pn> Trait<A1..An> for A0
// {
// type AssocType<Pn+1..Pm> where WC = T;
// }```
//
// ```
// forall<P0..Pm> {
// forall<Pn+1..Pm> {
// Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
// Implemented(A0: Trait<A1..An>) && WC
// }
// }
// ```

let item = tcx.associated_item(item_id);
debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
let impl_id = if let ty::AssociatedItemContainer::ImplContainer(impl_id) = item.container {
impl_id
} else {
bug!()
};
// `A0 as Trait<A1..An>`
let trait_ref = tcx.impl_trait_ref(impl_id).unwrap();
// `T`
let ty = tcx.type_of(item_id);
// `Implemented(A0: Trait<A1..An>)`
let trait_implemented = ty::Binder::dummy(ty::TraitPredicate { trait_ref }.lower());
// `WC`
let item_where_clauses = tcx.predicates_of(item_id).predicates.lower();
// `Implemented(A0: Trait<A1..An>) && WC`
let mut where_clauses = vec![trait_implemented];
where_clauses.extend(item_where_clauses);
// `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.name);
// `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
// `Normalize(... -> T) :- ...`
let clause = ProgramClause {
goal: normalize_goal,
hypotheses: tcx.mk_goals(
where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
),
};
Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))))
}

pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
if !tcx.features().rustc_attrs {
return;
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/chalkify/lower_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ trait Foo { }
#[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
impl<T: 'static> Foo for T where T: Iterator<Item = i32> { }

trait Bar {
type Assoc;
}

impl<T> Bar for T where T: Iterator<Item = i32> {
#[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
type Assoc = Vec<T>;
}

fn main() {
println!("hello");
}
8 changes: 7 additions & 1 deletion src/test/ui/chalkify/lower_impl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,11 @@ error: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error
error: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar).
--> $DIR/lower_impl.rs:23:5
|
LL | #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

0 comments on commit d703622

Please sign in to comment.