diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index c5be1b1174c43..70c152b40c0d2 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1387,6 +1387,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..36e60cee788dc 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, } @@ -118,10 +119,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(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(tcx.mk_clauses(iter::empty::())) + } + }, // FIXME: other constructions e.g. traits, associated types... _ => Lrc::new(tcx.mk_clauses(iter::empty::())), @@ -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>> { + // Rule Normalize-From-Impl (see rustc guide) + // + // ```impl Trait for A0 + // { + // type AssocType where WC = T; + // }``` + // + // ``` + // forall { + // forall { + // Normalize(>::AssocType -> T) :- + // Implemented(A0: Trait) && 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` + 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 item_where_clauses = tcx.predicates_of(item_id).predicates.lower(); + // `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) :- ...` + 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; 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..f253f9847d162 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) :- Implemented(T: Bar). + --> $DIR/lower_impl.rs:23:5 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Normalize(::Assoc == std::vec::Vec) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors