about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/dep_graph/dep_node.rs1
-rw-r--r--src/librustc/hir/map/def_collector.rs7
-rw-r--r--src/librustc/hir/map/definitions.rs15
-rw-r--r--src/librustc/ich/impls_ty.rs5
-rw-r--r--src/librustc/infer/canonical.rs71
-rw-r--r--src/librustc/session/config.rs2
-rw-r--r--src/librustc/traits/mod.rs12
-rw-r--r--src/librustc/traits/structural_impls.rs2
-rw-r--r--src/librustc/ty/context.rs12
-rw-r--r--src/librustc/ty/item_path.rs3
-rw-r--r--src/librustc/ty/maps/config.rs6
-rw-r--r--src/librustc/ty/maps/keys.rs9
-rw-r--r--src/librustc/ty/maps/mod.rs10
-rw-r--r--src/librustc/ty/maps/plumbing.rs1
-rw-r--r--src/librustc/ty/mod.rs5
-rw-r--r--src/librustc/util/ppaux.rs21
-rw-r--r--src/librustc_driver/driver.rs8
-rw-r--r--src/librustc_traits/lib.rs1
-rw-r--r--src/librustc_traits/lowering.rs232
-rw-r--r--src/librustc_traits/util.rs40
-rw-r--r--src/test/ui/chalkify/lower_env1.rs24
-rw-r--r--src/test/ui/chalkify/lower_env1.stderr24
-rw-r--r--src/test/ui/chalkify/lower_impl.rs4
-rw-r--r--src/test/ui/chalkify/lower_impl.stderr12
-rw-r--r--src/test/ui/chalkify/lower_trait.rs5
-rw-r--r--src/test/ui/chalkify/lower_trait.stderr27
-rw-r--r--src/test/ui/chalkify/lower_trait_higher_rank.rs5
-rw-r--r--src/test/ui/chalkify/lower_trait_higher_rank.stderr27
-rw-r--r--src/test/ui/chalkify/lower_trait_where_clause.rs8
-rw-r--r--src/test/ui/chalkify/lower_trait_where_clause.stderr50
30 files changed, 380 insertions, 269 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index b4f39439d5b..18bf54297af 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -655,6 +655,7 @@ define_dep_nodes!( <'tcx>
     [input] Features,
 
     [] ProgramClausesFor(DefId),
+    [] ProgramClausesForEnv(ParamEnv<'tcx>),
     [] WasmImportModuleMap(CrateNum),
     [] ForeignModules(CrateNum),
 
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 4bd857c73e6..bfe21549e45 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -107,8 +107,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         // information we encapsulate into
         let def_data = match i.node {
             ItemKind::Impl(..) => DefPathData::Impl,
+            ItemKind::Trait(..) => DefPathData::Trait(i.ident.name.as_str()),
             ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) |
-            ItemKind::Trait(..) | ItemKind::TraitAlias(..) |
+            ItemKind::TraitAlias(..) |
             ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
                 DefPathData::TypeNs(i.ident.name.as_str()),
             ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
@@ -222,7 +223,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         let def_data = match ti.node {
             TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
                 DefPathData::ValueNs(ti.ident.name.as_str()),
-            TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
+            TraitItemKind::Type(..) => DefPathData::AssocTypeInTrait(ti.ident.name.as_str()),
             TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
         };
 
@@ -240,7 +241,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         let def_data = match ii.node {
             ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
                 DefPathData::ValueNs(ii.ident.name.as_str()),
-            ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
+            ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_str()),
             ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
         };
 
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 1a2840de447..12f146ef491 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -212,6 +212,9 @@ impl DefKey {
         ::std::mem::discriminant(data).hash(&mut hasher);
         match *data {
             DefPathData::TypeNs(name) |
+            DefPathData::Trait(name) |
+            DefPathData::AssocTypeInTrait(name) |
+            DefPathData::AssocTypeInImpl(name) |
             DefPathData::ValueNs(name) |
             DefPathData::Module(name) |
             DefPathData::MacroDef(name) |
@@ -358,6 +361,12 @@ pub enum DefPathData {
     // Different kinds of items and item-like things:
     /// An impl
     Impl,
+    /// A trait
+    Trait(InternedString),
+    /// An associated type **declaration** (i.e., in a trait)
+    AssocTypeInTrait(InternedString),
+    /// An associated type **value** (i.e., in an impl)
+    AssocTypeInImpl(InternedString),
     /// Something in the type NS
     TypeNs(InternedString),
     /// Something in the value NS
@@ -639,6 +648,9 @@ impl DefPathData {
         use self::DefPathData::*;
         match *self {
             TypeNs(name) |
+            Trait(name) |
+            AssocTypeInTrait(name) |
+            AssocTypeInImpl(name) |
             ValueNs(name) |
             Module(name) |
             MacroDef(name) |
@@ -663,6 +675,9 @@ impl DefPathData {
         use self::DefPathData::*;
         let s = match *self {
             TypeNs(name) |
+            Trait(name) |
+            AssocTypeInTrait(name) |
+            AssocTypeInImpl(name) |
             ValueNs(name) |
             Module(name) |
             MacroDef(name) |
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 70c152b40c0..322cfd55510 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1352,10 +1352,6 @@ impl_stable_hash_for!(
     }
 );
 
-impl_stable_hash_for!(struct infer::canonical::QueryRegionConstraints<'tcx> {
-    region_outlives, ty_outlives
-});
-
 impl_stable_hash_for!(enum infer::canonical::Certainty {
     Proven, Ambiguous
 });
@@ -1417,6 +1413,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Goal<'tcx> {
                 quantifier.hash_stable(hcx, hasher);
                 goal.hash_stable(hcx, hasher);
             },
+            CannotProve => { },
         }
     }
 }
diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs
index 8ea6eb005a1..25f8b5d8c9c 100644
--- a/src/librustc/infer/canonical.rs
+++ b/src/librustc/infer/canonical.rs
@@ -42,7 +42,6 @@ use traits::{Obligation, ObligationCause, PredicateObligation};
 use ty::{self, CanonicalVar, Lift, Region, Slice, Ty, TyCtxt, TypeFlags};
 use ty::subst::{Kind, UnpackedKind};
 use ty::fold::{TypeFoldable, TypeFolder};
-use util::captures::Captures;
 
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_data_structures::fx::FxHashMap;
@@ -121,7 +120,7 @@ pub enum CanonicalTyVarKind {
 #[derive(Clone, Debug)]
 pub struct QueryResult<'tcx, R> {
     pub var_values: CanonicalVarValues<'tcx>,
-    pub region_constraints: QueryRegionConstraints<'tcx>,
+    pub region_constraints: Vec<QueryRegionConstraint<'tcx>>,
     pub certainty: Certainty,
     pub value: R,
 }
@@ -181,12 +180,7 @@ impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> {
     }
 }
 
-/// Subset of `RegionConstraintData` produced by trait query.
-#[derive(Clone, Debug, Default)]
-pub struct QueryRegionConstraints<'tcx> {
-    pub region_outlives: Vec<(Region<'tcx>, Region<'tcx>)>,
-    pub ty_outlives: Vec<(Ty<'tcx>, Region<'tcx>)>,
-}
+pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;
 
 /// Trait implemented by values that can be canonicalized. It mainly
 /// serves to identify the interning table we will use.
@@ -382,35 +376,29 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         &'a self,
         cause: &'a ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        unsubstituted_region_constraints: &'a QueryRegionConstraints<'tcx>,
+        unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>],
         result_subst: &'a CanonicalVarValues<'tcx>,
-    ) -> impl Iterator<Item = PredicateObligation<'tcx>> + Captures<'gcx> + 'a {
-        let QueryRegionConstraints {
-            region_outlives,
-            ty_outlives,
-        } = unsubstituted_region_constraints;
-
-        let region_obligations = region_outlives.iter().map(move |(r1, r2)| {
-            let r1 = substitute_value(self.tcx, result_subst, r1);
-            let r2 = substitute_value(self.tcx, result_subst, r2);
-            Obligation::new(
-                cause.clone(),
-                param_env,
-                ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r1, r2))),
-            )
-        });
-
-        let ty_obligations = ty_outlives.iter().map(move |(t1, r2)| {
-            let t1 = substitute_value(self.tcx, result_subst, t1);
+    ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a {
+        Box::new(unsubstituted_region_constraints.iter().map(move |constraint| {
+            let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
+            let k1 = substitute_value(self.tcx, result_subst, k1);
             let r2 = substitute_value(self.tcx, result_subst, r2);
-            Obligation::new(
-                cause.clone(),
-                param_env,
-                ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t1, r2))),
-            )
-        });
-
-        region_obligations.chain(ty_obligations)
+            match k1.unpack() {
+                UnpackedKind::Lifetime(r1) =>
+                    Obligation::new(
+                        cause.clone(),
+                        param_env,
+                        ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r1, r2))),
+                    ),
+
+                UnpackedKind::Type(t1) =>
+                    Obligation::new(
+                        cause.clone(),
+                        param_env,
+                        ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t1, r2))),
+                    ),
+            }
+        })) as Box<dyn Iterator<Item = _>>
     }
 
     /// Given two sets of values for the same set of canonical variables, unify them.
@@ -914,19 +902,6 @@ BraceStructTypeFoldableImpl! {
 }
 
 BraceStructTypeFoldableImpl! {
-    impl<'tcx> TypeFoldable<'tcx> for QueryRegionConstraints<'tcx> {
-        region_outlives, ty_outlives
-    }
-}
-
-BraceStructLiftImpl! {
-    impl<'a, 'tcx> Lift<'tcx> for QueryRegionConstraints<'a> {
-        type Lifted = QueryRegionConstraints<'tcx>;
-        region_outlives, ty_outlives
-    }
-}
-
-BraceStructTypeFoldableImpl! {
     impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> {
         var_values, region_constraints, certainty, value
     } where R: TypeFoldable<'tcx>,
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index e9fe94cdb4a..456e83f4700 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1289,6 +1289,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "tell the linker to strip debuginfo when building without debuginfo enabled."),
     share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
           "make the current crate share its generic instantiations"),
+    chalk: bool = (false, parse_bool, [TRACKED],
+          "enable the experimental Chalk-based trait solving engine"),
 }
 
 pub fn default_lib_output() -> CrateType {
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 8d2398d3409..5bfea163189 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -282,13 +282,16 @@ pub enum QuantifierKind {
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub enum Goal<'tcx> {
-    Implies(&'tcx Slice<Clause<'tcx>>, &'tcx Goal<'tcx>),
+    Implies(Clauses<'tcx>, &'tcx Goal<'tcx>),
     And(&'tcx Goal<'tcx>, &'tcx Goal<'tcx>),
     Not(&'tcx Goal<'tcx>),
     DomainGoal(DomainGoal<'tcx>),
-    Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>)
+    Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>),
+    CannotProve,
 }
 
+pub type Goals<'tcx> = &'tcx Slice<Goal<'tcx>>;
+
 impl<'tcx> Goal<'tcx> {
     pub fn from_poly_domain_goal<'a>(
         domain_goal: PolyDomainGoal<'tcx>,
@@ -318,6 +321,9 @@ pub enum Clause<'tcx> {
     ForAll(ty::Binder<ProgramClause<'tcx>>),
 }
 
+/// Multiple clauses.
+pub type Clauses<'tcx> = &'tcx Slice<Clause<'tcx>>;
+
 /// A "program clause" has the form `D :- G1, ..., Gn`. It is saying
 /// that the domain goal `D` is true if `G1...Gn` are provable. This
 /// is equivalent to the implication `G1..Gn => D`; we usually write
@@ -330,7 +336,7 @@ pub struct ProgramClause<'tcx> {
     pub goal: DomainGoal<'tcx>,
 
     /// ...if we can prove these hypotheses (there may be no hypotheses at all):
-    pub hypotheses: &'tcx Slice<Goal<'tcx>>,
+    pub hypotheses: Goals<'tcx>,
 }
 
 pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 31c5bf1bbad..1e3e4160de1 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -491,6 +491,7 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> {
                 // FIXME: appropriate binder names
                 write!(fmt, "{}<> {{ {} }}", qkind, goal.skip_binder())
             }
+            CannotProve => write!(fmt, "CannotProve"),
         }
     }
 }
@@ -557,6 +558,7 @@ EnumTypeFoldableImpl! {
         (traits::Goal::Not)(goal),
         (traits::Goal::DomainGoal)(domain_goal),
         (traits::Goal::Quantified)(qkind, goal),
+        (traits::Goal::CannotProve),
     }
 }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index f3a2aa51946..56669243f27 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -38,7 +38,7 @@ use ty::subst::{Kind, Substs};
 use ty::ReprOptions;
 use ty::Instance;
 use traits;
-use traits::{Clause, Goal};
+use traits::{Clause, Clauses, Goal, Goals};
 use ty::{self, Ty, TypeAndMut};
 use ty::{TyS, TypeVariants, Slice};
 use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region, Const};
@@ -2517,7 +2517,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> &'tcx Slice<Clause<'tcx>> {
+    pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> Clauses<'tcx> {
         if ts.len() == 0 {
             Slice::empty()
         } else {
@@ -2525,7 +2525,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> &'tcx Slice<Goal<'tcx>> {
+    pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> Goals<'tcx> {
         if ts.len() == 0 {
             Slice::empty()
         } else {
@@ -2579,13 +2579,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
     }
 
-    pub fn mk_clauses<I: InternAs<[Clause<'tcx>],
-        &'tcx Slice<Clause<'tcx>>>>(self, iter: I) -> I::Output {
+    pub fn mk_clauses<I: InternAs<[Clause<'tcx>], Clauses<'tcx>>>(self, iter: I) -> I::Output {
         iter.intern_with(|xs| self.intern_clauses(xs))
     }
 
-    pub fn mk_goals<I: InternAs<[Goal<'tcx>],
-        &'tcx Slice<Goal<'tcx>>>>(self, iter: I) -> I::Output {
+    pub fn mk_goals<I: InternAs<[Goal<'tcx>], Goals<'tcx>>>(self, iter: I) -> I::Output {
         iter.intern_with(|xs| self.intern_goals(xs))
     }
 
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index 8189064db69..2819141c81b 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -204,6 +204,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             // finer-grained distinctions, e.g. between enum/struct).
             data @ DefPathData::Misc |
             data @ DefPathData::TypeNs(..) |
+            data @ DefPathData::Trait(..) |
+            data @ DefPathData::AssocTypeInTrait(..) |
+            data @ DefPathData::AssocTypeInImpl(..) |
             data @ DefPathData::ValueNs(..) |
             data @ DefPathData::Module(..) |
             data @ DefPathData::TypeParam(..) |
diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs
index fea7de955e0..735fe06560f 100644
--- a/src/librustc/ty/maps/config.rs
+++ b/src/librustc/ty/maps/config.rs
@@ -717,6 +717,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for_env<'tcx> {
+    fn describe(_tcx: TyCtxt, _: ty::ParamEnv<'tcx>) -> String {
+        format!("generating chalk-style clauses for param env")
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::wasm_import_module_map<'tcx> {
     fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
         format!("wasm import module map")
diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs
index b8167ec9186..72f2cb49abc 100644
--- a/src/librustc/ty/maps/keys.rs
+++ b/src/librustc/ty/maps/keys.rs
@@ -154,6 +154,15 @@ impl<'tcx> Key for Ty<'tcx> {
     }
 }
 
+impl<'tcx> Key for ty::ParamEnv<'tcx> {
+    fn map_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, _: TyCtxt) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
     fn map_crate(&self) -> CrateNum {
         self.value.map_crate()
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index 0ab9f16dab4..92d23d4338f 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -37,8 +37,8 @@ use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution};
 use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
 use traits::query::normalize::NormalizationResult;
 use traits::specialization_graph;
-use traits::Clause;
-use ty::{self, CrateInherentImpls, ParamEnvAnd, Slice, Ty, TyCtxt};
+use traits::Clauses;
+use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
 use ty::steal::Steal;
 use ty::subst::Substs;
 use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
@@ -445,7 +445,11 @@ define_maps! { <'tcx>
 
     [] fn features_query: features_node(CrateNum) -> Lrc<feature_gate::Features>,
 
-    [] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc<&'tcx Slice<Clause<'tcx>>>,
+    [] fn program_clauses_for: ProgramClausesFor(DefId) -> Clauses<'tcx>,
+
+    [] fn program_clauses_for_env: ProgramClausesForEnv(
+        ty::ParamEnv<'tcx>
+    ) -> Clauses<'tcx>,
 
     [] fn wasm_custom_sections: WasmCustomSections(CrateNum) -> Lrc<Vec<DefId>>,
     [] fn wasm_import_module_map: WasmImportModuleMap(CrateNum)
diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs
index 8d6c7474a9f..70fbd17e6cb 100644
--- a/src/librustc/ty/maps/plumbing.rs
+++ b/src/librustc/ty/maps/plumbing.rs
@@ -978,6 +978,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::DropckOutlives |
         DepKind::SubstituteNormalizeAndTestPredicates |
         DepKind::InstanceDefSizeEstimate |
+        DepKind::ProgramClausesForEnv |
 
         // This one should never occur in this context
         DepKind::Null => {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index c3d2d5675de..1524d4b9e7f 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1138,6 +1138,11 @@ pub struct ProjectionPredicate<'tcx> {
 pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>;
 
 impl<'tcx> PolyProjectionPredicate<'tcx> {
+    /// Returns the def-id of the associated item being projected.
+    pub fn item_def_id(&self) -> DefId {
+        self.skip_binder().projection_ty.item_def_id
+    }
+
     pub fn to_poly_trait_ref(&self, tcx: TyCtxt) -> PolyTraitRef<'tcx> {
         // Note: unlike with TraitRef::to_poly_trait_ref(),
         // self.0.trait_ref is permitted to have escaping regions.
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index dd478967b18..84e3358ff13 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -268,14 +268,31 @@ impl PrintContext {
             loop {
                 let key = tcx.def_key(item_def_id);
                 match key.disambiguated_data.data {
+                    DefPathData::AssocTypeInTrait(_) |
+                    DefPathData::AssocTypeInImpl(_) |
+                    DefPathData::Trait(_) |
                     DefPathData::TypeNs(_) => {
                         break;
                     }
-                    DefPathData::ValueNs(_) | DefPathData::EnumVariant(_) => {
+                    DefPathData::ValueNs(_) |
+                    DefPathData::EnumVariant(_) => {
                         is_value_path = true;
                         break;
                     }
-                    _ => {
+                    DefPathData::CrateRoot |
+                    DefPathData::Misc |
+                    DefPathData::Impl |
+                    DefPathData::Module(_) |
+                    DefPathData::MacroDef(_) |
+                    DefPathData::ClosureExpr |
+                    DefPathData::TypeParam(_) |
+                    DefPathData::LifetimeDef(_) |
+                    DefPathData::Field(_) |
+                    DefPathData::StructCtor |
+                    DefPathData::Initializer |
+                    DefPathData::ImplTrait |
+                    DefPathData::Typeof |
+                    DefPathData::GlobalMetaData(_) => {
                         // if we're making a symbol for something, there ought
                         // to be a value or type-def or something in there
                         // *somewhere*
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 2c781fda4ed..2fb811eba1e 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -1155,6 +1155,10 @@ where
                 }
             });
 
+            time(sess, "dumping chalk-like clauses", || {
+                rustc_traits::lowering::dump_program_clauses(tcx);
+            });
+
             time(sess, "MIR effect checking", || {
                 for def_id in tcx.body_owners() {
                     mir::transform::check_unsafety::check_unsafety(tcx, def_id)
@@ -1178,10 +1182,6 @@ where
 
             time(sess, "lint checking", || lint::check_crate(tcx));
 
-            time(sess, "dumping chalk-like clauses", || {
-                rustc_traits::lowering::dump_program_clauses(tcx)
-            });
-
             return Ok(f(tcx, analysis, rx, tcx.sess.compile_status()));
         },
     )
diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs
index 8136f6857a5..90c870096e1 100644
--- a/src/librustc_traits/lib.rs
+++ b/src/librustc_traits/lib.rs
@@ -37,6 +37,7 @@ pub fn provide(p: &mut Providers) {
         normalize_ty_after_erasing_regions:
             normalize_erasing_regions::normalize_ty_after_erasing_regions,
         program_clauses_for: lowering::program_clauses_for,
+        program_clauses_for_env: lowering::program_clauses_for_env,
         ..*p
     };
 }
diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs
index 36e60cee788..b6a086f609d 100644
--- a/src/librustc_traits/lowering.rs
+++ b/src/librustc_traits/lowering.rs
@@ -8,14 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::hir::{self, ImplPolarity};
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc::ty::{self, Slice, TyCtxt};
+use rustc::hir::map::definitions::DefPathData;
+use rustc::hir::{self, ImplPolarity};
+use rustc::traits::{Clause, Clauses, DomainGoal, Goal, PolyDomainGoal, ProgramClause,
+                    WhereClauseAtom};
 use rustc::ty::subst::Substs;
-use rustc::traits::{WhereClauseAtom, PolyDomainGoal, DomainGoal, ProgramClause, Clause, Goal};
+use rustc::ty::{self, Slice, TyCtxt};
+use rustc_data_structures::fx::FxHashSet;
+use std::mem;
 use syntax::ast;
-use rustc_data_structures::sync::Lrc;
 
 use std::iter;
 
@@ -24,7 +27,10 @@ trait Lower<T> {
     fn lower(&self) -> T;
 }
 
-impl<T, U> Lower<Vec<U>> for Vec<T> where T: Lower<U> {
+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()
     }
@@ -42,7 +48,10 @@ impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::ProjectionPredicate<'tcx> {
     }
 }
 
-impl<'tcx, T> Lower<DomainGoal<'tcx>> for T where T: Lower<WhereClauseAtom<'tcx>> {
+impl<'tcx, T> Lower<DomainGoal<'tcx>> for T
+where
+    T: Lower<WhereClauseAtom<'tcx>>,
+{
     fn lower(&self) -> DomainGoal<'tcx> {
         DomainGoal::Holds(self.lower())
     }
@@ -67,7 +76,8 @@ impl<'tcx> Lower<DomainGoal<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
 /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
 /// `Binder<Holds(Implemented(TraitPredicate))>`.
 impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
-    where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>
+where
+    T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>,
 {
     fn lower(&self) -> PolyDomainGoal<'tcx> {
         self.map_bound_ref(|p| p.lower())
@@ -84,10 +94,9 @@ impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
             TypeOutlives(predicate) => predicate.lower(),
             Projection(predicate) => predicate.lower(),
             WellFormed(ty) => ty::Binder::dummy(DomainGoal::WellFormedTy(*ty)),
-            ObjectSafe(..) |
-            ClosureKind(..) |
-            Subtype(..) |
-            ConstEvaluatable(..) => unimplemented!(),
+            ObjectSafe(..) | ClosureKind(..) | Subtype(..) | ConstEvaluatable(..) => {
+                unimplemented!()
+            }
         }
     }
 }
@@ -104,44 +113,88 @@ impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
         use self::DomainGoal::*;
         match self {
             Holds(wc_atom) => FromEnv(wc_atom),
-            WellFormed(..) |
-            FromEnv(..) |
-            WellFormedTy(..) |
-            FromEnvTy(..) |
-            Normalize(..) |
-            RegionOutlives(..) |
-            TypeOutlives(..) => self,
+            WellFormed(..) | FromEnv(..) | WellFormedTy(..) | FromEnvTy(..) | Normalize(..)
+            | RegionOutlives(..) | TypeOutlives(..) => self,
         }
     }
 }
 
-crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                       -> Lrc<&'tcx Slice<Clause<'tcx>>>
-{
-    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
-    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>()))
-            }
-        },
+crate fn program_clauses_for<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    def_id: DefId,
+) -> Clauses<'tcx> {
+    match tcx.def_key(def_id).disambiguated_data.data {
+        DefPathData::Trait(_) => program_clauses_for_trait(tcx, def_id),
+        DefPathData::Impl => program_clauses_for_impl(tcx, def_id),
+        DefPathData::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx, def_id),
+        _ => Slice::empty(),
+    }
+}
 
-        // FIXME: other constructions e.g. traits, associated types...
-        _ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
+crate fn program_clauses_for_env<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> Clauses<'tcx> {
+    debug!("program_clauses_for_env(param_env={:?})", param_env);
+
+    let mut last_round = FxHashSet();
+    last_round.extend(
+        param_env
+            .caller_bounds
+            .iter()
+            .flat_map(|&p| predicate_def_id(p)),
+    );
+
+    let mut closure = last_round.clone();
+    let mut next_round = FxHashSet();
+    while !last_round.is_empty() {
+        next_round.extend(
+            last_round
+                .drain()
+                .flat_map(|def_id| {
+                    tcx.predicates_of(def_id)
+                        .instantiate_identity(tcx)
+                        .predicates
+                })
+                .flat_map(|p| predicate_def_id(p))
+                .filter(|&def_id| closure.insert(def_id)),
+        );
+        mem::swap(&mut next_round, &mut last_round);
+    }
+
+    debug!("program_clauses_for_env: closure = {:#?}", closure);
+
+    return tcx.mk_clauses(
+        closure
+            .into_iter()
+            .flat_map(|def_id| tcx.program_clauses_for(def_id).iter().cloned()),
+    );
+
+    /// Given that `predicate` is in the environment, returns the
+    /// def-id of something (e.g., a trait, associated item, etc)
+    /// whose predicates can also be assumed to be true. We will
+    /// compute the transitive closure of such things.
+    fn predicate_def_id<'tcx>(predicate: ty::Predicate<'tcx>) -> Option<DefId> {
+        match predicate {
+            ty::Predicate::Trait(predicate) => Some(predicate.def_id()),
+
+            ty::Predicate::Projection(projection) => Some(projection.item_def_id()),
+
+            ty::Predicate::WellFormed(..)
+            | ty::Predicate::RegionOutlives(..)
+            | ty::Predicate::TypeOutlives(..)
+            | ty::Predicate::ObjectSafe(..)
+            | ty::Predicate::ClosureKind(..)
+            | ty::Predicate::Subtype(..)
+            | ty::Predicate::ConstEvaluatable(..) => None,
+        }
     }
 }
 
-fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                       -> Lrc<&'tcx Slice<Clause<'tcx>>>
-{
+fn program_clauses_for_trait<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    def_id: DefId,
+) -> Clauses<'tcx> {
     // `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
 
     // Rule Implemented-From-Env (see rustc guide)
@@ -156,8 +209,8 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
     let trait_pred = ty::TraitPredicate {
         trait_ref: ty::TraitRef {
             def_id,
-            substs: Substs::identity_for_item(tcx, def_id)
-        }
+            substs: Substs::identity_for_item(tcx, def_id),
+        },
     };
     // `FromEnv(Self: Trait<P1..Pn>)`
     let from_env = Goal::from(DomainGoal::FromEnv(trait_pred.lower()));
@@ -169,9 +222,7 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
         goal: impl_trait,
         hypotheses: tcx.mk_goals(iter::once(from_env)),
     };
-    let clauses = iter::once(
-        Clause::ForAll(ty::Binder::dummy(implemented_from_env))
-    );
+    let clauses = iter::once(Clause::ForAll(ty::Binder::dummy(implemented_from_env)));
 
     // Rule Implied-Bound-From-Trait
     //
@@ -186,11 +237,11 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
     // FIXME: Remove the [1..] slice; this is a hack because the query
     // predicates_of currently includes the trait itself (`Self: Trait<P1..Pn>`).
     let where_clauses = &tcx.predicates_of(def_id).predicates;
-    let implied_bound_clauses =
-        where_clauses[1..].into_iter()
+    let implied_bound_clauses = where_clauses[1..]
+        .into_iter()
         .map(|wc| implied_bound_from_trait(tcx, trait_pred, wc));
 
-    Lrc::new(tcx.mk_clauses(clauses.chain(implied_bound_clauses)))
+    tcx.mk_clauses(clauses.chain(implied_bound_clauses))
 }
 
 /// For a given `where_clause`, returns a clause `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`.
@@ -203,19 +254,15 @@ fn implied_bound_from_trait<'a, 'tcx>(
     let impl_trait = DomainGoal::FromEnv(WhereClauseAtom::Implemented(trait_pred));
 
     // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
-    Clause::ForAll(
-        where_clause.lower().map_bound(|goal| ProgramClause {
-            goal: goal.into_from_env_goal(),
-            hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))),
-        })
-    )
+    Clause::ForAll(where_clause.lower().map_bound(|goal| ProgramClause {
+        goal: goal.into_from_env_goal(),
+        hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))),
+    }))
 }
 
-fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                      -> Lrc<&'tcx Slice<Clause<'tcx>>>
-{
+fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Clauses<'tcx> {
     if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
-        return Lrc::new(tcx.mk_clauses(iter::empty::<Clause>()));
+        return Slice::empty();
     }
 
     // Rule Implemented-From-Impl (see rustc guide)
@@ -231,23 +278,25 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId
     let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
     // `Implemented(A0: Trait<A1..An>)`
     let trait_pred = ty::TraitPredicate { trait_ref }.lower();
-     // `WC`
+    // `WC`
     let where_clauses = tcx.predicates_of(def_id).predicates.lower();
 
-     // `Implemented(A0: Trait<A1..An>) :- WC`
+    // `Implemented(A0: Trait<A1..An>) :- WC`
     let clause = ProgramClause {
         goal: trait_pred,
         hypotheses: tcx.mk_goals(
-            where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
-        )
+            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)))))
+    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>>> {
+) -> Clauses<'tcx> {
     // Rule Normalize-From-Impl (see rustc guide)
     //
     // ```impl<P0..Pn> Trait<A1..An> for A0
@@ -290,10 +339,12 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
     let clause = ProgramClause {
         goal: normalize_goal,
         hypotheses: tcx.mk_goals(
-            where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
+            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)))))
+    tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
 }
 
 pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
@@ -302,27 +353,54 @@ pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     }
 
     let mut visitor = ClauseDumper { tcx };
-    tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
+    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 > {
+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 {
+            let mut clauses = None;
+
             if attr.check_name("rustc_dump_program_clauses") {
-                let clauses = self.tcx.program_clauses_for(def_id);
-                for clause in *clauses {
-                    // Skip the top-level binder for a less verbose output
-                    let program_clause = match clause {
-                        Clause::Implies(program_clause) => program_clause,
-                        Clause::ForAll(program_clause) => program_clause.skip_binder(),
-                    };
-                    self.tcx.sess.struct_span_err(attr.span, &format!("{}", program_clause)).emit();
+                clauses = Some(self.tcx.program_clauses_for(def_id));
+            }
+
+            if attr.check_name("rustc_dump_env_program_clauses") {
+                let param_env = self.tcx.param_env(def_id);
+                clauses = Some(self.tcx.program_clauses_for_env(param_env));
+            }
+
+            if let Some(clauses) = clauses {
+                let mut err = self.tcx
+                    .sess
+                    .struct_span_err(attr.span, "program clause dump");
+
+                let mut strings: Vec<_> = clauses
+                    .iter()
+                    .map(|clause| {
+                        // Skip the top-level binder for a less verbose output
+                        let program_clause = match clause {
+                            Clause::Implies(program_clause) => program_clause,
+                            Clause::ForAll(program_clause) => program_clause.skip_binder(),
+                        };
+                        format!("{}", program_clause)
+                    })
+                    .collect();
+
+                strings.sort();
+
+                for string in strings {
+                    err.note(&string);
                 }
+
+                err.emit();
             }
         }
     }
diff --git a/src/librustc_traits/util.rs b/src/librustc_traits/util.rs
index bff070ab73d..f25906a7bca 100644
--- a/src/librustc_traits/util.rs
+++ b/src/librustc_traits/util.rs
@@ -9,8 +9,7 @@
 // except according to those terms.
 
 use rustc::infer::InferCtxt;
-use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryRegionConstraints,
-                              QueryResult};
+use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryResult};
 use rustc::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc::traits::{FulfillmentContext, TraitEngine};
 use rustc::traits::query::NoSolution;
@@ -62,7 +61,7 @@ where
 
     let region_obligations = infcx.take_registered_region_obligations();
 
-    let (region_outlives, ty_outlives) = infcx.with_region_constraints(|region_constraints| {
+    let region_constraints = infcx.with_region_constraints(|region_constraints| {
         let RegionConstraintData {
             constraints,
             verifys,
@@ -72,24 +71,32 @@ where
         assert!(verifys.is_empty());
         assert!(givens.is_empty());
 
-        let region_outlives: Vec<_> = constraints
+        let mut outlives: Vec<_> = constraints
             .into_iter()
             .map(|(k, _)| match *k {
-                Constraint::VarSubVar(v1, v2) => {
-                    (tcx.mk_region(ty::ReVar(v1)), tcx.mk_region(ty::ReVar(v2)))
+                Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
+                    tcx.mk_region(ty::ReVar(v1)).into(),
+                    tcx.mk_region(ty::ReVar(v2)),
+                ),
+                Constraint::VarSubReg(v1, r2) => {
+                    ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v1)).into(), r2)
                 }
-                Constraint::VarSubReg(v1, r2) => (tcx.mk_region(ty::ReVar(v1)), r2),
-                Constraint::RegSubVar(r1, v2) => (r1, tcx.mk_region(ty::ReVar(v2))),
-                Constraint::RegSubReg(r1, r2) => (r1, r2),
+                Constraint::RegSubVar(r1, v2) => {
+                    ty::OutlivesPredicate(r1.into(), tcx.mk_region(ty::ReVar(v2)))
+                }
+                Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r1.into(), r2),
             })
+            .map(ty::Binder) // no bound regions in the code above
             .collect();
 
-        let ty_outlives: Vec<_> = region_obligations
-            .into_iter()
-            .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
-            .collect();
+        outlives.extend(
+            region_obligations
+                .into_iter()
+                .map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region))
+                .map(ty::Binder) // no bound regions in the code above
+        );
 
-        (region_outlives, ty_outlives)
+        outlives
     });
 
     let certainty = if ambig_errors.is_empty() {
@@ -100,10 +107,7 @@ where
 
     let (canonical_result, _) = infcx.canonicalize_response(&QueryResult {
         var_values: inference_vars,
-        region_constraints: QueryRegionConstraints {
-            region_outlives,
-            ty_outlives,
-        },
+        region_constraints,
         certainty,
         value: answer,
     });
diff --git a/src/test/ui/chalkify/lower_env1.rs b/src/test/ui/chalkify/lower_env1.rs
new file mode 100644
index 00000000000..fc20ad0e08b
--- /dev/null
+++ b/src/test/ui/chalkify/lower_env1.rs
@@ -0,0 +1,24 @@
+// 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)]
+#![allow(dead_code)]
+
+trait Foo { }
+
+#[rustc_dump_program_clauses] //~ ERROR program clause dump
+trait Bar where Self: Foo { }
+
+#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
+fn bar<T: Bar>() {
+}
+
+fn main() {
+}
diff --git a/src/test/ui/chalkify/lower_env1.stderr b/src/test/ui/chalkify/lower_env1.stderr
new file mode 100644
index 00000000000..3a280f85e76
--- /dev/null
+++ b/src/test/ui/chalkify/lower_env1.stderr
@@ -0,0 +1,24 @@
+error: program clause dump
+  --> $DIR/lower_env1.rs:16:1
+   |
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: FromEnv(Self: Bar) :- FromEnv(Self: Bar).
+   = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
+   = note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
+
+error: program clause dump
+  --> $DIR/lower_env1.rs:19:1
+   |
+LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: FromEnv(Self: Bar) :- FromEnv(Self: Bar).
+   = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
+   = note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
+   = note: Implemented(Self: Foo) :- FromEnv(Self: Foo).
+   = note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized).
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/chalkify/lower_impl.rs b/src/test/ui/chalkify/lower_impl.rs
index 671d77efbea..b38b87cdb12 100644
--- a/src/test/ui/chalkify/lower_impl.rs
+++ b/src/test/ui/chalkify/lower_impl.rs
@@ -12,7 +12,7 @@
 
 trait Foo { }
 
-#[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
+#[rustc_dump_program_clauses] //~ ERROR program clause dump
 impl<T: 'static> Foo for T where T: Iterator<Item = i32> { }
 
 trait Bar {
@@ -20,7 +20,7 @@ trait Bar {
 }
 
 impl<T> Bar for T where T: Iterator<Item = i32> {
-    #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
+    #[rustc_dump_program_clauses] //~ ERROR program clause dump
     type Assoc = Vec<T>;
 }
 
diff --git a/src/test/ui/chalkify/lower_impl.stderr b/src/test/ui/chalkify/lower_impl.stderr
index f253f9847d1..c497d76f8d4 100644
--- a/src/test/ui/chalkify/lower_impl.stderr
+++ b/src/test/ui/chalkify/lower_impl.stderr
@@ -1,14 +1,18 @@
-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).
+error: program clause dump
   --> $DIR/lower_impl.rs:15:1
    |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized).
 
-error: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar).
+error: program clause dump
   --> $DIR/lower_impl.rs:23:5
    |
-LL |     #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
+LL |     #[rustc_dump_program_clauses] //~ ERROR program clause dump
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar).
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/chalkify/lower_trait.rs b/src/test/ui/chalkify/lower_trait.rs
index 74feb0105cc..7c0f233a645 100644
--- a/src/test/ui/chalkify/lower_trait.rs
+++ b/src/test/ui/chalkify/lower_trait.rs
@@ -10,10 +10,7 @@
 
 #![feature(rustc_attrs)]
 
-#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
-                              //~| ERROR FromEnv
-                              //~| ERROR FromEnv
-                              //~| ERROR FromEnv
+#[rustc_dump_program_clauses] //~ ERROR program clause dump
 trait Foo<S, T, U> {
     fn s(S) -> S;
     fn t(T) -> T;
diff --git a/src/test/ui/chalkify/lower_trait.stderr b/src/test/ui/chalkify/lower_trait.stderr
index 45753c3bb90..55cd9699b06 100644
--- a/src/test/ui/chalkify/lower_trait.stderr
+++ b/src/test/ui/chalkify/lower_trait.stderr
@@ -1,26 +1,13 @@
-error: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>).
+error: program clause dump
   --> $DIR/lower_trait.rs:13:1
    |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
-  --> $DIR/lower_trait.rs:13:1
-   |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
-  --> $DIR/lower_trait.rs:13:1
    |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
-  --> $DIR/lower_trait.rs:13:1
-   |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
+   = note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
+   = note: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
+   = note: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>).
 
-error: aborting due to 4 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/chalkify/lower_trait_higher_rank.rs b/src/test/ui/chalkify/lower_trait_higher_rank.rs
index e5eaf4591ec..47e9398d364 100644
--- a/src/test/ui/chalkify/lower_trait_higher_rank.rs
+++ b/src/test/ui/chalkify/lower_trait_higher_rank.rs
@@ -10,10 +10,7 @@
 
 #![feature(rustc_attrs)]
 
-#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
-                              //~| ERROR FromEnv
-                              //~| ERROR FromEnv
-                              //~| ERROR FromEnv
+#[rustc_dump_program_clauses] //~ ERROR program clause dump
 trait Foo<F> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8
 {
     fn s(F) -> F;
diff --git a/src/test/ui/chalkify/lower_trait_higher_rank.stderr b/src/test/ui/chalkify/lower_trait_higher_rank.stderr
index 9aed0c018c9..7f6f503c6ff 100644
--- a/src/test/ui/chalkify/lower_trait_higher_rank.stderr
+++ b/src/test/ui/chalkify/lower_trait_higher_rank.stderr
@@ -1,26 +1,13 @@
-error: Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>).
+error: program clause dump
   --> $DIR/lower_trait_higher_rank.rs:13:1
    |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(F: std::marker::Sized) :- FromEnv(Self: Foo<F>).
-  --> $DIR/lower_trait_higher_rank.rs:13:1
-   |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>).
-  --> $DIR/lower_trait_higher_rank.rs:13:1
    |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>).
-  --> $DIR/lower_trait_higher_rank.rs:13:1
-   |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: FromEnv(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>).
+   = note: FromEnv(F: std::marker::Sized) :- FromEnv(Self: Foo<F>).
+   = note: FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>).
+   = note: Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>).
 
-error: aborting due to 4 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/chalkify/lower_trait_where_clause.rs b/src/test/ui/chalkify/lower_trait_where_clause.rs
index b2ce3ca48b2..67ee7c28b6a 100644
--- a/src/test/ui/chalkify/lower_trait_where_clause.rs
+++ b/src/test/ui/chalkify/lower_trait_where_clause.rs
@@ -13,13 +13,7 @@
 use std::fmt::{Debug, Display};
 use std::borrow::Borrow;
 
-#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
-                              //~| ERROR FromEnv
-                              //~| ERROR FromEnv
-                              //~| ERROR FromEnv
-                              //~| ERROR FromEnv
-                              //~| ERROR RegionOutlives
-                              //~| ERROR TypeOutlives
+#[rustc_dump_program_clauses] //~ ERROR program clause dump
 trait Foo<'a, 'b, S, T, U> where S: Debug, T: Borrow<U>, U: ?Sized, 'a: 'b, U: 'b {
     fn s(S) -> S;
     fn t(T) -> T;
diff --git a/src/test/ui/chalkify/lower_trait_where_clause.stderr b/src/test/ui/chalkify/lower_trait_where_clause.stderr
index a9ecaec3aff..68bc2ddf293 100644
--- a/src/test/ui/chalkify/lower_trait_where_clause.stderr
+++ b/src/test/ui/chalkify/lower_trait_where_clause.stderr
@@ -1,44 +1,16 @@
-error: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+error: program clause dump
   --> $DIR/lower_trait_where_clause.rs:16:1
    |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
-  --> $DIR/lower_trait_where_clause.rs:16:1
-   |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
-  --> $DIR/lower_trait_where_clause.rs:16:1
-   |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(S: std::fmt::Debug) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
-  --> $DIR/lower_trait_where_clause.rs:16:1
-   |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(T: std::borrow::Borrow<U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
-  --> $DIR/lower_trait_where_clause.rs:16:1
-   |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
-  --> $DIR/lower_trait_where_clause.rs:16:1
    |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
-  --> $DIR/lower_trait_where_clause.rs:16:1
-   |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
+   = note: FromEnv(S: std::fmt::Debug) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+   = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+   = note: FromEnv(T: std::borrow::Borrow<U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+   = note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+   = note: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+   = note: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+   = note: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+
+error: aborting due to previous error