[] GetSymbolExportLevel(DefId),
[input] Features,
+
+ [] ProgramClausesFor(DefId),
);
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
impl_stable_hash_for!(enum infer::canonical::Certainty {
Proven, Ambiguous
});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::WhereClauseAtom<'tcx> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ use traits::WhereClauseAtom::*;
+
+ mem::discriminant(self).hash_stable(hcx, hasher);
+ match *self {
+ Implemented(ref trait_ref) => trait_ref.hash_stable(hcx, hasher),
+ ProjectionEq(ref projection) => projection.hash_stable(hcx, hasher),
+ }
+ }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::DomainGoal<'tcx> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ use traits::DomainGoal::*;
+
+ mem::discriminant(self).hash_stable(hcx, hasher);
+ match *self {
+ Holds(ref where_clause) |
+ WellFormed(ref where_clause) |
+ FromEnv(ref where_clause) => where_clause.hash_stable(hcx, hasher),
+
+ WellFormedTy(ref ty) => ty.hash_stable(hcx, hasher),
+ FromEnvTy(ref ty) => ty.hash_stable(hcx, hasher),
+ RegionOutlives(ref predicate) => predicate.hash_stable(hcx, hasher),
+ TypeOutlives(ref predicate) => predicate.hash_stable(hcx, hasher),
+ }
+ }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::LeafGoal<'tcx> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ use traits::LeafGoal::*;
+
+ mem::discriminant(self).hash_stable(hcx, hasher);
+ match *self {
+ DomainGoal(ref domain_goal) => domain_goal.hash_stable(hcx, hasher),
+ }
+ }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Goal<'tcx> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ use traits::Goal::*;
+
+ mem::discriminant(self).hash_stable(hcx, hasher);
+ match *self {
+ Implies(ref hypotheses, ref goal) => {
+ hypotheses.hash_stable(hcx, hasher);
+ goal.hash_stable(hcx, hasher);
+ },
+ And(ref goal1, ref goal2) => {
+ goal1.hash_stable(hcx, hasher);
+ goal2.hash_stable(hcx, hasher);
+ }
+ Not(ref goal) => goal.hash_stable(hcx, hasher),
+ Leaf(ref leaf_goal) => leaf_goal.hash_stable(hcx, hasher),
+ Quantified(quantifier, ref goal) => {
+ quantifier.hash_stable(hcx, hasher);
+ goal.hash_stable(hcx, hasher);
+ },
+ }
+ }
+}
+
+impl_stable_hash_for!(enum traits::QuantifierKind {
+ Universal,
+ Existential
+});
+
+impl_stable_hash_for!(struct traits::ProgramClause<'tcx> {
+ consequence,
+ conditions
+});
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use hir::{self, ImplPolarity};
+use hir::def_id::DefId;
+use hir::intravisit::{self, NestedVisitorMap, Visitor};
+use ty::{self, PolyTraitPredicate, TraitPredicate, PolyProjectionPredicate, TyCtxt, Predicate};
+use super::{DomainGoal, ProgramClause, WhereClauseAtom};
+use rustc_data_structures::sync::Lrc;
+use syntax::ast;
+
+trait Lower<T> {
+ fn lower(&self) -> T;
+}
+
+impl<T, U> Lower<Vec<U>> for Vec<T> where T: Lower<U> {
+ fn lower(&self) -> Vec<U> {
+ self.iter().map(|item| item.lower()).collect()
+ }
+}
+
+impl<'tcx> Lower<WhereClauseAtom<'tcx>> for PolyTraitPredicate<'tcx> {
+ fn lower(&self) -> WhereClauseAtom<'tcx> {
+ WhereClauseAtom::Implemented(*self)
+ }
+}
+
+impl<'tcx> Lower<WhereClauseAtom<'tcx>> for PolyProjectionPredicate<'tcx> {
+ fn lower(&self) -> WhereClauseAtom<'tcx> {
+ WhereClauseAtom::ProjectionEq(*self)
+ }
+}
+
+impl<'tcx, T> Lower<DomainGoal<'tcx>> for T where T: Lower<WhereClauseAtom<'tcx>> {
+ fn lower(&self) -> DomainGoal<'tcx> {
+ DomainGoal::Holds(self.lower())
+ }
+}
+
+impl<'tcx> Lower<DomainGoal<'tcx>> for Predicate<'tcx> {
+ fn lower(&self) -> DomainGoal<'tcx> {
+ use self::Predicate::*;
+
+ match *self {
+ Trait(predicate) => predicate.lower(),
+ RegionOutlives(predicate) => DomainGoal::RegionOutlives(predicate),
+ TypeOutlives(predicate) => DomainGoal::TypeOutlives(predicate),
+ Projection(predicate) => predicate.lower(),
+ WellFormed(ty) => DomainGoal::WellFormedTy(ty),
+ ObjectSafe(..) |
+ ClosureKind(..) |
+ Subtype(..) |
+ ConstEvaluatable(..) => unimplemented!(),
+
+ }
+ }
+}
+
+pub fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+ -> Lrc<Vec<ProgramClause<'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::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
+ _ => Lrc::new(vec![]),
+ }
+}
+
+fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+ -> Lrc<Vec<ProgramClause<'tcx>>>
+{
+ if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
+ return Lrc::new(vec![]);
+ }
+
+ let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
+ let trait_ref = ty::Binder(TraitPredicate { trait_ref }).lower();
+ let where_clauses = tcx.predicates_of(def_id).predicates.lower();
+
+ let clause = ProgramClause {
+ consequence: trait_ref,
+ conditions: where_clauses.into_iter().map(|wc| wc.into()).collect(),
+ };
+
+ Lrc::new(vec![clause])
+}
+
+pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ if !tcx.features().rustc_attrs {
+ return;
+ }
+
+ let mut visitor = ClauseDumper { tcx };
+ tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
+}
+
+struct ClauseDumper<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+}
+
+impl <'a, 'tcx> ClauseDumper<'a, 'tcx > {
+ fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
+ let def_id = self.tcx.hir.local_def_id(node_id);
+ for attr in attrs {
+ if attr.check_name("rustc_dump_program_clauses") {
+ let clauses = self.tcx.program_clauses_for(def_id);
+ for clause in &*clauses {
+ self.tcx.sess.struct_span_err(attr.span, &format!("{}", clause)).emit();
+ }
+ }
+ }
+ }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for ClauseDumper<'a, 'tcx> {
+ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+ NestedVisitorMap::OnlyBodies(&self.tcx.hir)
+ }
+
+ fn visit_item(&mut self, item: &'tcx hir::Item) {
+ self.process_attrs(item.id, &item.attrs);
+ intravisit::walk_item(self, item);
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+ self.process_attrs(trait_item.id, &trait_item.attrs);
+ intravisit::walk_trait_item(self, trait_item);
+ }
+
+ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
+ self.process_attrs(impl_item.id, &impl_item.attrs);
+ intravisit::walk_impl_item(self, impl_item);
+ }
+
+ fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
+ self.process_attrs(s.id, &s.attrs);
+ intravisit::walk_struct_field(self, s);
+ }
+}
use rustc_data_structures::sync::Lrc;
use std::rc::Rc;
+use std::convert::From;
use syntax::ast;
use syntax_pos::{Span, DUMMY_SP};
mod structural_impls;
pub mod trans;
mod util;
+mod lowering;
pub mod query;
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub enum WhereClauseAtom<'tcx> {
+ Implemented(ty::PolyTraitPredicate<'tcx>),
+ ProjectionEq(ty::PolyProjectionPredicate<'tcx>),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub enum DomainGoal<'tcx> {
+ Holds(WhereClauseAtom<'tcx>),
+ WellFormed(WhereClauseAtom<'tcx>),
+ FromEnv(WhereClauseAtom<'tcx>),
+ WellFormedTy(Ty<'tcx>),
+ FromEnvTy(Ty<'tcx>),
+ RegionOutlives(ty::PolyRegionOutlivesPredicate<'tcx>),
+ TypeOutlives(ty::PolyTypeOutlivesPredicate<'tcx>),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub enum LeafGoal<'tcx> {
+ DomainGoal(DomainGoal<'tcx>),
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum QuantifierKind {
+ Universal,
+ Existential,
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub enum Goal<'tcx> {
+ Implies(Vec<DomainGoal<'tcx>>, Box<Goal<'tcx>>),
+ And(Box<Goal<'tcx>>, Box<Goal<'tcx>>),
+ Not(Box<Goal<'tcx>>),
+ Leaf(LeafGoal<'tcx>),
+ Quantified(QuantifierKind, Box<ty::Binder<Goal<'tcx>>>)
+}
+
+impl<'tcx> From<DomainGoal<'tcx>> for Goal<'tcx> {
+ fn from(domain_goal: DomainGoal<'tcx>) -> Self {
+ Goal::Leaf(LeafGoal::DomainGoal(domain_goal))
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct ProgramClause<'tcx> {
+ pub consequence: DomainGoal<'tcx>,
+ pub conditions: Vec<Goal<'tcx>>,
+}
+
+pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ lowering::dump_program_clauses(tcx)
+}
+
pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
#[derive(Clone,Debug)]
specialization_graph_of: specialize::specialization_graph_provider,
specializes: specialize::specializes,
trans_fulfill_obligation: trans::trans_fulfill_obligation,
+ program_clauses_for: lowering::program_clauses_for,
vtable_methods,
substitute_normalize_and_test_predicates,
..*providers
obligations
} where T: TypeFoldable<'tcx>
}
+
+impl<'tcx> fmt::Display for traits::WhereClauseAtom<'tcx> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ use traits::WhereClauseAtom::*;
+ match *self {
+ Implemented(ref trait_ref) => write!(fmt, "Implemented({})", trait_ref),
+ ProjectionEq(ref projection) => write!(fmt, "ProjectionEq({})", projection),
+ }
+ }
+}
+
+impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ use traits::DomainGoal::*;
+ use traits::WhereClauseAtom::*;
+ match *self {
+ Holds(wc) => write!(fmt, "{}", wc),
+ WellFormed(Implemented(ref trait_ref)) => write!(fmt, "WellFormed({})", trait_ref),
+ WellFormed(ProjectionEq(ref projection)) => write!(fmt, "WellFormed({})", projection),
+ FromEnv(Implemented(ref trait_ref)) => write!(fmt, "FromEnv({})", trait_ref),
+ FromEnv(ProjectionEq(ref projection)) => write!(fmt, "FromEnv({})", projection),
+ WellFormedTy(ref ty) => write!(fmt, "WellFormed({})", ty),
+ FromEnvTy(ref ty) => write!(fmt, "FromEnv({})", ty),
+ RegionOutlives(ref predicate) => write!(fmt, "RegionOutlives({})", predicate),
+ TypeOutlives(ref predicate) => write!(fmt, "TypeOutlives({})", predicate),
+ }
+ }
+}
+
+impl fmt::Display for traits::QuantifierKind {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ use traits::QuantifierKind::*;
+ match *self {
+ Universal => write!(fmt, "forall"),
+ Existential => write!(fmt, "exists"),
+ }
+ }
+}
+
+impl<'tcx> fmt::Display for traits::LeafGoal<'tcx> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ use traits::LeafGoal::*;
+ match *self {
+ DomainGoal(ref domain_goal) => write!(fmt, "{}", domain_goal),
+ }
+ }
+}
+
+impl<'tcx> fmt::Display for traits::Goal<'tcx> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ use traits::Goal::*;
+ match *self {
+ Implies(ref hypotheses, ref goal) => {
+ write!(fmt, "if (")?;
+ for (index, hyp) in hypotheses.iter().enumerate() {
+ if index > 0 {
+ write!(fmt, ", ")?;
+ }
+ write!(fmt, "{}", hyp)?;
+ }
+ write!(fmt, ") {{ {} }}", goal)
+ }
+ And(ref goal1, ref goal2) => write!(fmt, "({}, {})", goal1, goal2),
+ Not(ref goal) => write!(fmt, "not {{ {} }}", goal),
+ Leaf(ref goal) => write!(fmt, "{}", goal),
+ Quantified(qkind, ref goal) => {
+ // FIXME: appropriate binder names
+ write!(fmt, "{}<> {{ {} }}", qkind, goal.skip_binder())
+ }
+ }
+ }
+}
+
+impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "{}", self.consequence)?;
+ if self.conditions.is_empty() {
+ write!(fmt, ".")?;
+ } else {
+ write!(fmt, " :- ")?;
+ for (index, condition) in self.conditions.iter().enumerate() {
+ if index > 0 {
+ write!(fmt, ", ")?;
+ }
+ write!(fmt, "{}", condition)?;
+ }
+ }
+ Ok(())
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::WhereClauseAtom<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ use traits::WhereClauseAtom::*;
+ match *self {
+ Implemented(ref trait_ref) => Implemented(trait_ref.fold_with(folder)),
+ ProjectionEq(ref projection) => ProjectionEq(projection.fold_with(folder)),
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ use traits::WhereClauseAtom::*;
+ match *self {
+ Implemented(ref trait_ref) => trait_ref.visit_with(visitor),
+ ProjectionEq(ref projection) => projection.visit_with(visitor),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::DomainGoal<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ use traits::DomainGoal::*;
+ match *self {
+ Holds(ref wc) => Holds(wc.fold_with(folder)),
+ WellFormed(ref wc) => WellFormed(wc.fold_with(folder)),
+ FromEnv(ref wc) => FromEnv(wc.fold_with(folder)),
+ WellFormedTy(ref ty) => WellFormedTy(ty.fold_with(folder)),
+ FromEnvTy(ref ty) => FromEnvTy(ty.fold_with(folder)),
+ RegionOutlives(ref predicate) => RegionOutlives(predicate.fold_with(folder)),
+ TypeOutlives(ref predicate) => TypeOutlives(predicate.fold_with(folder)),
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ use traits::DomainGoal::*;
+ match *self {
+ Holds(ref wc) |
+ WellFormed(ref wc) |
+ FromEnv(ref wc) => wc.visit_with(visitor),
+ WellFormedTy(ref ty) |
+ FromEnvTy(ref ty) => ty.visit_with(visitor),
+ RegionOutlives(ref predicate) => predicate.visit_with(visitor),
+ TypeOutlives(ref predicate) => predicate.visit_with(visitor),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::LeafGoal<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ use traits::LeafGoal::*;
+ match *self {
+ DomainGoal(ref domain_goal) => DomainGoal(domain_goal.fold_with(folder)),
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ use traits::LeafGoal::*;
+ match *self {
+ DomainGoal(ref domain_goal) => domain_goal.visit_with(visitor),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ use traits::Goal::*;
+ match *self {
+ Implies(ref hypotheses, ref goal) => {
+ Implies(
+ hypotheses.iter().map(|hyp| hyp.fold_with(folder)).collect(),
+ goal.fold_with(folder)
+ )
+ },
+ And(ref goal1, ref goal2) => And(goal1.fold_with(folder), goal2.fold_with(folder)),
+ Not(ref goal) => Not(goal.fold_with(folder)),
+ Leaf(ref leaf_goal) => Leaf(leaf_goal.fold_with(folder)),
+ Quantified(qkind, ref goal) => Quantified(qkind, goal.fold_with(folder)),
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ use traits::Goal::*;
+ match *self {
+ Implies(ref hypotheses, ref goal) => {
+ hypotheses.iter().any(|hyp| hyp.visit_with(visitor)) || goal.visit_with(visitor)
+ }
+ And(ref goal1, ref goal2) => goal1.visit_with(visitor) || goal2.visit_with(visitor),
+ Not(ref goal) => goal.visit_with(visitor),
+ Leaf(ref leaf_goal) => leaf_goal.visit_with(visitor),
+ Quantified(_, ref goal) => goal.visit_with(visitor),
+ }
+ }
+}
}
}
+impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for<'tcx> {
+ fn describe(_tcx: TyCtxt, _: DefId) -> String {
+ format!("generating chalk-style clauses")
+ }
+}
+
macro_rules! impl_disk_cacheable_query(
($query_name:ident, |$key:tt| $cond:expr) => {
impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> {
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
use traits::query::normalize::NormalizationResult;
use traits::specialization_graph;
+use traits::ProgramClause;
use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use ty::steal::Steal;
use ty::subst::Substs;
-> usize,
[] fn features_query: features_node(CrateNum) -> Lrc<feature_gate::Features>,
+
+ [] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc<Vec<ProgramClause<'tcx>>>,
}
//////////////////////////////////////////////////////////////////////
DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); }
DepKind::Features => { force!(features_query, LOCAL_CRATE); }
+
+ DepKind::ProgramClausesFor => { force!(program_clauses_for, def_id!()); }
}
true
time(sess, "lint checking", || lint::check_crate(tcx));
+ time(time_passes, "dumping chalk-like clauses", || traits::dump_program_clauses(tcx));
+
return Ok(f(tcx, analysis, rx, tcx.sess.compile_status()));
})
}
across crates and will never be stable",
cfg_fn!(rustc_attrs))),
+ ("rustc_dump_program_clauses", Whitelisted, Gated(Stability::Unstable,
+ "rustc_attrs",
+ "the `#[rustc_dump_program_clauses]` \
+ attribute is just used for rustc unit \
+ tests and will never be stable",
+ cfg_fn!(rustc_attrs))),
+
// RFC #2094
("nll", Whitelisted, Gated(Stability::Unstable,
"nll",
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_attrs)]
+
+trait Foo { }
+
+#[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
+impl<T: 'static> Foo for T where T: Iterator<Item = i32> { }
+
+fn main() {
+ println!("hello");
+}
--- /dev/null
+error: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized)
+ --> $DIR/lower_impl.rs:15:1
+ |
+LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+