diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 99ac5869b29..b568273c650 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 32fd93cf20a..8d2398d3409 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 523cd42940e..31c5bf1bbad 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 df6793e8a60..b418a0aca9a 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 2083ada6d2d..671d77efbea 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 b5d791d640a..5a32b8567b9 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