From 5a73fd5e1f7915548bfb63688e97b94f5461e285 Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Tue, 3 Apr 2018 17:53:13 +0200 Subject: [PATCH 1/5] Implement Chalk lowering rule Normalize-From-Impl --- src/librustc/ich/impls_ty.rs | 1 + src/librustc/traits/mod.rs | 1 + src/librustc/traits/structural_impls.rs | 2 + src/librustc_traits/lowering.rs | 65 +++++++++++++++++++++++-- src/test/ui/chalkify/lower_impl.rs | 9 ++++ src/test/ui/chalkify/lower_impl.stderr | 8 ++- 6 files changed, 81 insertions(+), 5 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 99ac5869b2969..b568273c650d3 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1388,6 +1388,7 @@ impl<'a, 'tcx> HashStable> 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), diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 32fd93cf20a1f..8d2398d34090d 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -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>), diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 523cd42940e27..31c5bf1bbad84 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -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), @@ -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), diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index df6793e8a604c..b418a0aca9a3a 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -118,10 +118,20 @@ crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI -> Lrc<&'tcx Slice>> { 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(vec![]), + } + hir::map::Node::NodeImplItem(item) => { + if let hir::ImplItemKind::Type(..) = item.node { + program_clauses_for_associated_type(tcx, def_id) + } else { + Lrc::new(vec![]) + } + }, // FIXME: other constructions e.g. traits, associated types... _ => Lrc::new(tcx.mk_clauses(iter::empty::())), @@ -233,6 +243,53 @@ 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<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: DefId) + -> Lrc>> { + // Rule Normalize-From-Impl (see rustc guide) + // + // ```impl Trait for A0 + // where WC + // { + // type AssocType where WC1 = T; + // }``` + // + // ``` + // forall { + // forall { + // Normalize(>::AssocType -> T) :- + // WC && WC1 + // } + // } + // ``` + + 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` + let trait_ref = tcx.impl_trait_ref(impl_id).unwrap(); + // `T` + let ty = tcx.type_of(item_id); + // `WC` + let impl_where_clauses = tcx.predicates_of(impl_id).predicates.lower(); + // `WC1` + let item_where_clauses = tcx.predicates_of(item_id).predicates.lower(); + // `WC && WC1` + let mut where_clauses = vec![]; + where_clauses.extend(impl_where_clauses); + where_clauses.extend(item_where_clauses); + // `>::AssocType` + let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.name); + // `Normalize(>::AssocType -> T)` + let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty }); + // `Normalize(... -> T) :- WC && WC1` + let clause = Clause::Implies(where_clauses, normalize_goal); + Lrc::new(vec![clause]) +} + pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { if !tcx.features().rustc_attrs { return; diff --git a/src/test/ui/chalkify/lower_impl.rs b/src/test/ui/chalkify/lower_impl.rs index 2083ada6d2de5..671d77efbea3a 100644 --- a/src/test/ui/chalkify/lower_impl.rs +++ b/src/test/ui/chalkify/lower_impl.rs @@ -15,6 +15,15 @@ trait Foo { } #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :- impl Foo for T where T: Iterator { } +trait Bar { + type Assoc; +} + +impl Bar for T where T: Iterator { + #[rustc_dump_program_clauses] //~ ERROR Normalize(::Assoc == std::vec::Vec) :- + type Assoc = Vec; +} + fn main() { println!("hello"); } diff --git a/src/test/ui/chalkify/lower_impl.stderr b/src/test/ui/chalkify/lower_impl.stderr index b5d791d640ada..5a32b8567b99f 100644 --- a/src/test/ui/chalkify/lower_impl.stderr +++ b/src/test/ui/chalkify/lower_impl.stderr @@ -4,5 +4,11 @@ error: Implemented(T: Foo) :- ProjectionEq(::Item == i LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: Normalize(::Assoc == std::vec::Vec) :- ProjectionEq(::Item == i32), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized). + --> $DIR/lower_impl.rs:23:5 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Normalize(::Assoc == std::vec::Vec) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors From 27393b121054575824417bc8609c1602a08a9d08 Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Sat, 7 Apr 2018 02:04:28 +0200 Subject: [PATCH 2/5] Improve function name. --- src/librustc_traits/lowering.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index b418a0aca9a3a..cbb02e98c3cd1 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -127,7 +127,7 @@ crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI } hir::map::Node::NodeImplItem(item) => { if let hir::ImplItemKind::Type(..) = item.node { - program_clauses_for_associated_type(tcx, def_id) + program_clauses_for_associated_type_value(tcx, def_id) } else { Lrc::new(vec![]) } @@ -243,8 +243,10 @@ 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<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: DefId) - -> Lrc>> { +pub fn program_clauses_for_associated_type_value<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + item_id: DefId, +) -> Lrc>> { // Rule Normalize-From-Impl (see rustc guide) // // ```impl Trait for A0 From ecd41976fc5a13e8c9a706496d714f655a5ab995 Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Wed, 11 Apr 2018 14:27:00 +0200 Subject: [PATCH 3/5] Rebase and update code. --- src/librustc_traits/lowering.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index cbb02e98c3cd1..1b73cd480990c 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -108,6 +108,7 @@ impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> { FromEnv(..) | WellFormedTy(..) | FromEnvTy(..) | + Normalize(..) | RegionOutlives(..) | TypeOutlives(..) => self, } @@ -288,8 +289,11 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( // `Normalize(>::AssocType -> T)` let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty }); // `Normalize(... -> T) :- WC && WC1` - let clause = Clause::Implies(where_clauses, normalize_goal); - Lrc::new(vec![clause]) + let clause = ProgramClause { + goal: normalize_goal, + hypotheses: where_clauses.into_iter().map(|wc| wc.into()).collect(), + }; + Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))]) } pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { From de475582c4dc1c8f532eed578d574979283f1c42 Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Wed, 11 Apr 2018 21:20:25 +0200 Subject: [PATCH 4/5] Stop duplicating where clauses from impl's. --- src/librustc_traits/lowering.rs | 16 +++++++--------- src/test/ui/chalkify/lower_impl.stderr | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index 1b73cd480990c..9da2c49ee5d7a 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -251,16 +251,15 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( // Rule Normalize-From-Impl (see rustc guide) // // ```impl Trait for A0 - // where WC // { - // type AssocType where WC1 = T; + // type AssocType where WC = T; // }``` // // ``` // forall { // forall { // Normalize(>::AssocType -> T) :- - // WC && WC1 + // Implemented(A0: Trait) && WC // } // } // ``` @@ -276,19 +275,18 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( let trait_ref = tcx.impl_trait_ref(impl_id).unwrap(); // `T` let ty = tcx.type_of(item_id); + // `Implemented(A0: Trait)` + let trait_implemented = ty::Binder::dummy(ty::TraitPredicate { trait_ref }.lower()); // `WC` - let impl_where_clauses = tcx.predicates_of(impl_id).predicates.lower(); - // `WC1` let item_where_clauses = tcx.predicates_of(item_id).predicates.lower(); - // `WC && WC1` - let mut where_clauses = vec![]; - where_clauses.extend(impl_where_clauses); + // `Implemented(A0: Trait) && WC` + let mut where_clauses = vec![trait_implemented]; where_clauses.extend(item_where_clauses); // `>::AssocType` let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.name); // `Normalize(>::AssocType -> T)` let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty }); - // `Normalize(... -> T) :- WC && WC1` + // `Normalize(... -> T) :- ...` let clause = ProgramClause { goal: normalize_goal, hypotheses: where_clauses.into_iter().map(|wc| wc.into()).collect(), diff --git a/src/test/ui/chalkify/lower_impl.stderr b/src/test/ui/chalkify/lower_impl.stderr index 5a32b8567b99f..f253f9847d162 100644 --- a/src/test/ui/chalkify/lower_impl.stderr +++ b/src/test/ui/chalkify/lower_impl.stderr @@ -4,7 +4,7 @@ error: Implemented(T: Foo) :- ProjectionEq(::Item == i LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Normalize(::Assoc == std::vec::Vec) :- ProjectionEq(::Item == i32), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized). +error: Normalize(::Assoc == std::vec::Vec) :- Implemented(T: Bar). --> $DIR/lower_impl.rs:23:5 | LL | #[rustc_dump_program_clauses] //~ ERROR Normalize(::Assoc == std::vec::Vec) :- From b7c4a57465b8d5599c7e799e1aafe12a458156f8 Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Sun, 15 Apr 2018 23:49:41 +0200 Subject: [PATCH 5/5] Rebase and fix conflicts. --- src/librustc_traits/lowering.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index 9da2c49ee5d7a..36e60cee788dc 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -124,13 +124,13 @@ crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI 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(vec![]), + _ => Lrc::new(tcx.mk_clauses(iter::empty::())), } hir::map::Node::NodeImplItem(item) => { if let hir::ImplItemKind::Type(..) = item.node { program_clauses_for_associated_type_value(tcx, def_id) } else { - Lrc::new(vec![]) + Lrc::new(tcx.mk_clauses(iter::empty::())) } }, @@ -247,7 +247,7 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId pub fn program_clauses_for_associated_type_value<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: DefId, -) -> Lrc>> { +) -> Lrc<&'tcx Slice>> { // Rule Normalize-From-Impl (see rustc guide) // // ```impl Trait for A0 @@ -289,9 +289,11 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( // `Normalize(... -> T) :- ...` let clause = ProgramClause { goal: normalize_goal, - hypotheses: where_clauses.into_iter().map(|wc| wc.into()).collect(), + hypotheses: tcx.mk_goals( + where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx)) + ), }; - Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))]) + 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>) {