about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-09-13 16:28:22 +0000
committerbors <bors@rust-lang.org>2020-09-13 16:28:22 +0000
commit7402a394471a6738a40fea7d4f1891666e5a80c5 (patch)
tree69d3f436d6e60abe00a606a3a42a2e78a09ad83a
parenta055c5a1bd95e029e9b31891db63b6dc8258b472 (diff)
parent7dad29d6868914484be04cb054863261903bba58 (diff)
downloadrust-7402a394471a6738a40fea7d4f1891666e5a80c5.tar.gz
rust-7402a394471a6738a40fea7d4f1891666e5a80c5.zip
Auto merge of #76244 - vandenheuvel:remove__paramenv__def_id, r=nikomatsakis
Removing the `def_id` field from hot `ParamEnv` to make it smaller

This PR addresses https://github.com/rust-lang/rust/issues/74865.
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs3
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs2
-rw-r--r--compiler/rustc_infer/src/traits/util.rs3
-rw-r--r--compiler/rustc_lint/src/builtin.rs3
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/traits/chalk.rs30
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/context.rs26
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs3
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs44
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs5
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs8
-rw-r--r--compiler/rustc_mir/src/transform/qualify_min_const_fn.rs3
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs142
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs3
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs107
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs9
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs3
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs3
-rw-r--r--compiler/rustc_ty/src/ty.rs135
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs16
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs3
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs1
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs3
-rw-r--r--compiler/rustc_typeck/src/outlives/explicit.rs3
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/test/ui/chalkify/type_inference.stderr4
-rw-r--r--src/test/ui/infinite/infinite-tag-type-recursion.stderr2
35 files changed, 288 insertions, 337 deletions
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index a1e7f1fa3e5..de98cccf256 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -26,7 +26,8 @@ pub fn explicit_outlives_bounds<'tcx>(
             | ty::PredicateAtom::ClosureKind(..)
             | ty::PredicateAtom::TypeOutlives(..)
             | ty::PredicateAtom::ConstEvaluatable(..)
-            | ty::PredicateAtom::ConstEquate(..) => None,
+            | ty::PredicateAtom::ConstEquate(..)
+            | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
             ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
                 Some(OutlivesBound::RegionSubRegion(r_b, r_a))
             }
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 7e7c8588ffb..a3c4920fa8a 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -57,7 +57,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
 
 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(PredicateObligation<'_>, 40);
+static_assert_size!(PredicateObligation<'_>, 32);
 
 pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
 pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 93fc7f1f3b8..9c0d934a035 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -236,6 +236,9 @@ impl Elaborator<'tcx> {
                         .map(|predicate| predicate_obligation(predicate, None)),
                 );
             }
+            ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+                // Nothing to elaborate
+            }
         }
     }
 }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index d18d89ed641..61ecd13c307 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1228,7 +1228,8 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     ClosureKind(..) |
                     Subtype(..) |
                     ConstEvaluatable(..) |
-                    ConstEquate(..) => continue,
+                    ConstEquate(..) |
+                    TypeWellFormedFromEnv(..) => continue,
                 };
                 if predicate.is_global() {
                     cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 719f0322fd7..15e3110bc85 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1399,7 +1399,7 @@ rustc_queries! {
         }
 
         query evaluate_goal(
-            goal: traits::ChalkCanonicalGoal<'tcx>
+            goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx>
         ) -> Result<
             &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
             NoSolution
diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs
index 763b078e770..d8507d08c1b 100644
--- a/compiler/rustc_middle/src/traits/chalk.rs
+++ b/compiler/rustc_middle/src/traits/chalk.rs
@@ -6,14 +6,11 @@
 //! interned Chalk types.
 
 use rustc_middle::mir::interpret::ConstValue;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtDef, TyCtxt};
 
 use rustc_hir::def_id::DefId;
 use rustc_target::spec::abi::Abi;
 
-use smallvec::SmallVec;
-
 use std::cmp::Ordering;
 use std::fmt;
 use std::hash::{Hash, Hasher};
@@ -376,31 +373,10 @@ impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> {
     type Interner = Self;
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
-pub enum ChalkEnvironmentClause<'tcx> {
-    /// A normal rust `ty::Predicate` in the environment.
-    Predicate(ty::Predicate<'tcx>),
-    /// A special clause in the environment that gets lowered to
-    /// `chalk_ir::FromEnv::Ty`.
-    TypeFromEnv(Ty<'tcx>),
-}
-
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ChalkEnvironmentClause<'tcx>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
-        folder.tcx().intern_chalk_environment_clause_list(&v)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.iter().any(|t| t.visit_with(visitor))
-    }
-}
-/// We have to elaborate the environment of a chalk goal *before*
-/// canonicalization. This type wraps the predicate and the elaborated
-/// environment.
+/// A chalk environment and goal.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
 pub struct ChalkEnvironmentAndGoal<'tcx> {
-    pub environment: &'tcx ty::List<ChalkEnvironmentClause<'tcx>>,
+    pub environment: &'tcx ty::List<ty::Predicate<'tcx>>,
     pub goal: ty::Predicate<'tcx>,
 }
 
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index f86403fa502..ae89b68942c 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -26,14 +26,12 @@ use std::rc::Rc;
 
 pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
 
-pub type ChalkCanonicalGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>;
+pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>;
 
 pub use self::ImplSource::*;
 pub use self::ObligationCauseCode::*;
 
-pub use self::chalk::{
-    ChalkEnvironmentAndGoal, ChalkEnvironmentClause, RustInterner as ChalkRustInterner,
-};
+pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner};
 
 /// Depending on the stage of compilation, we want projection to be
 /// more or less conservative.
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index aa34dedc4b2..aacf61e5b42 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -91,8 +91,6 @@ pub struct CtxtInterners<'tcx> {
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
     const_: InternedSet<'tcx, Const<'tcx>>,
-
-    chalk_environment_clause_list: InternedSet<'tcx, List<traits::ChalkEnvironmentClause<'tcx>>>,
 }
 
 impl<'tcx> CtxtInterners<'tcx> {
@@ -110,7 +108,6 @@ impl<'tcx> CtxtInterners<'tcx> {
             projs: Default::default(),
             place_elems: Default::default(),
             const_: Default::default(),
-            chalk_environment_clause_list: Default::default(),
         }
     }
 
@@ -2041,7 +2038,7 @@ direct_interners! {
 }
 
 macro_rules! slice_interners {
-    ($($field:ident: $method:ident($ty:ty)),+) => (
+    ($($field:ident: $method:ident($ty:ty)),+ $(,)?) => (
         $(impl<'tcx> TyCtxt<'tcx> {
             pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
                 self.interners.$field.intern_ref(v, || {
@@ -2060,8 +2057,6 @@ slice_interners!(
     predicates: _intern_predicates(Predicate<'tcx>),
     projs: _intern_projs(ProjectionKind),
     place_elems: _intern_place_elems(PlaceElem<'tcx>),
-    chalk_environment_clause_list:
-        _intern_chalk_environment_clause_list(traits::ChalkEnvironmentClause<'tcx>)
 );
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -2460,13 +2455,6 @@ impl<'tcx> TyCtxt<'tcx> {
         if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) }
     }
 
-    pub fn intern_chalk_environment_clause_list(
-        self,
-        ts: &[traits::ChalkEnvironmentClause<'tcx>],
-    ) -> &'tcx List<traits::ChalkEnvironmentClause<'tcx>> {
-        if ts.is_empty() { List::empty() } else { self._intern_chalk_environment_clause_list(ts) }
-    }
-
     pub fn mk_fn_sig<I>(
         self,
         inputs: I,
@@ -2524,18 +2512,6 @@ impl<'tcx> TyCtxt<'tcx> {
         self.mk_substs(iter::once(self_ty.into()).chain(rest.iter().cloned()))
     }
 
-    pub fn mk_chalk_environment_clause_list<
-        I: InternAs<
-            [traits::ChalkEnvironmentClause<'tcx>],
-            &'tcx List<traits::ChalkEnvironmentClause<'tcx>>,
-        >,
-    >(
-        self,
-        iter: I,
-    ) -> I::Output {
-        iter.intern_with(|xs| self.intern_chalk_environment_clause_list(xs))
-    }
-
     /// Walks upwards from `id` to find a node which might change lint levels with attributes.
     /// It stops at `bound` and just returns it if reached.
     pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId {
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index f7871c4fffd..c9a4022330a 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -249,6 +249,9 @@ impl FlagComputation {
                 self.add_const(expected);
                 self.add_const(found);
             }
+            ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+                self.add_ty(ty);
+            }
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 29fa3f9bb65..8283deb3ecc 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1155,6 +1155,11 @@ pub enum PredicateAtom<'tcx> {
 
     /// Constants must be equal. The first component is the const that is expected.
     ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
+
+    /// Represents a type found in the environment that we can use for implied bounds.
+    ///
+    /// Only used for Chalk.
+    TypeWellFormedFromEnv(Ty<'tcx>),
 }
 
 impl<'tcx> PredicateAtom<'tcx> {
@@ -1450,7 +1455,8 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateAtom::ClosureKind(..)
             | PredicateAtom::TypeOutlives(..)
             | PredicateAtom::ConstEvaluatable(..)
-            | PredicateAtom::ConstEquate(..) => None,
+            | PredicateAtom::ConstEquate(..)
+            | PredicateAtom::TypeWellFormedFromEnv(..) => None,
         }
     }
 
@@ -1465,7 +1471,8 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateAtom::ObjectSafe(..)
             | PredicateAtom::ClosureKind(..)
             | PredicateAtom::ConstEvaluatable(..)
-            | PredicateAtom::ConstEquate(..) => None,
+            | PredicateAtom::ConstEquate(..)
+            | PredicateAtom::TypeWellFormedFromEnv(..) => None,
         }
     }
 }
@@ -1738,11 +1745,6 @@ pub struct ParamEnv<'tcx> {
     ///
     /// Note: This is packed, use the reveal() method to access it.
     packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, traits::Reveal, true>,
-
-    /// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`,
-    /// register that `def_id` (useful for transitioning to the chalk trait
-    /// solver).
-    pub def_id: Option<DefId>,
 }
 
 unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
@@ -1767,7 +1769,6 @@ impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
         f.debug_struct("ParamEnv")
             .field("caller_bounds", &self.caller_bounds())
             .field("reveal", &self.reveal())
-            .field("def_id", &self.def_id)
             .finish()
     }
 }
@@ -1776,23 +1777,16 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         self.caller_bounds().hash_stable(hcx, hasher);
         self.reveal().hash_stable(hcx, hasher);
-        self.def_id.hash_stable(hcx, hasher);
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
     fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        ParamEnv::new(
-            self.caller_bounds().fold_with(folder),
-            self.reveal().fold_with(folder),
-            self.def_id.fold_with(folder),
-        )
+        ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.caller_bounds().visit_with(visitor)
-            || self.reveal().visit_with(visitor)
-            || self.def_id.visit_with(visitor)
+        self.caller_bounds().visit_with(visitor) || self.reveal().visit_with(visitor)
     }
 }
 
@@ -1803,7 +1797,7 @@ impl<'tcx> ParamEnv<'tcx> {
     /// type-checking.
     #[inline]
     pub fn empty() -> Self {
-        Self::new(List::empty(), Reveal::UserFacing, None)
+        Self::new(List::empty(), Reveal::UserFacing)
     }
 
     #[inline]
@@ -1825,17 +1819,13 @@ impl<'tcx> ParamEnv<'tcx> {
     /// or invoke `param_env.with_reveal_all()`.
     #[inline]
     pub fn reveal_all() -> Self {
-        Self::new(List::empty(), Reveal::All, None)
+        Self::new(List::empty(), Reveal::All)
     }
 
     /// Construct a trait environment with the given set of predicates.
     #[inline]
-    pub fn new(
-        caller_bounds: &'tcx List<Predicate<'tcx>>,
-        reveal: Reveal,
-        def_id: Option<DefId>,
-    ) -> Self {
-        ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal), def_id }
+    pub fn new(caller_bounds: &'tcx List<Predicate<'tcx>>, reveal: Reveal) -> Self {
+        ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) }
     }
 
     pub fn with_user_facing(mut self) -> Self {
@@ -1857,12 +1847,12 @@ impl<'tcx> ParamEnv<'tcx> {
             return self;
         }
 
-        ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All, self.def_id)
+        ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All)
     }
 
     /// Returns this same environment but with no caller bounds.
     pub fn without_caller_bounds(self) -> Self {
-        Self::new(List::empty(), self.reveal(), self.def_id)
+        Self::new(List::empty(), self.reveal())
     }
 
     /// Creates a suitable environment in which to perform trait
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 538c07b9bde..9562d437914 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2096,6 +2096,11 @@ define_print_and_forward_display! {
                 print(c2),
                 write("`"))
             }
+            ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+                p!(write("the type `"),
+                print(ty),
+                write("` is found in the environment"))
+            }
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index f8627e2f1b6..afbf805975c 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -260,6 +260,9 @@ impl fmt::Debug for ty::PredicateAtom<'tcx> {
                 write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
             }
             ty::PredicateAtom::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
+            ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+                write!(f, "TypeWellFormedFromEnv({:?})", ty)
+            }
         }
     }
 }
@@ -536,6 +539,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateAtom<'a> {
             ty::PredicateAtom::ConstEquate(c1, c2) => {
                 tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateAtom::ConstEquate(c1, c2))
             }
+            ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+                tcx.lift(&ty).map(ty::PredicateAtom::TypeWellFormedFromEnv)
+            }
         }
     }
 }
@@ -551,7 +557,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
     type Lifted = ty::ParamEnv<'tcx>;
     fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         tcx.lift(&self.caller_bounds())
-            .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.def_id))
+            .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal()))
     }
 }
 
diff --git a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs
index 7d9611e0731..5e102f5151d 100644
--- a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs
+++ b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs
@@ -30,7 +30,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
                 | ty::PredicateAtom::WellFormed(_)
                 | ty::PredicateAtom::Projection(_)
                 | ty::PredicateAtom::ConstEvaluatable(..)
-                | ty::PredicateAtom::ConstEquate(..) => continue,
+                | ty::PredicateAtom::ConstEquate(..)
+                | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
                 ty::PredicateAtom::ObjectSafe(_) => {
                     bug!("object safe predicate on function: {:#?}", predicate)
                 }
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 9cf3bbd94e0..28697ec4e3b 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -1261,7 +1261,8 @@ crate fn required_region_bounds(
                 | ty::PredicateAtom::ClosureKind(..)
                 | ty::PredicateAtom::RegionOutlives(..)
                 | ty::PredicateAtom::ConstEvaluatable(..)
-                | ty::PredicateAtom::ConstEquate(..) => None,
+                | ty::PredicateAtom::ConstEquate(..)
+                | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
                 ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
                     // Search for a bound of the form `erased_self_ty
                     // : 'a`, but be wary of something like `for<'a>
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index ad8e9d9faa6..6b87bc4f34a 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -373,14 +373,12 @@ impl AutoTraitFinder<'tcx> {
                 computed_preds.clone().chain(user_computed_preds.iter().cloned()),
             )
             .map(|o| o.predicate);
-            new_env =
-                ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal(), None);
+            new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal());
         }
 
         let final_user_env = ty::ParamEnv::new(
             tcx.mk_predicates(user_computed_preds.into_iter()),
             user_env.reveal(),
-            None,
         );
         debug!(
             "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index 0097097707f..adc8ae59086 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -4,12 +4,11 @@ use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::InferCtxt;
 use crate::traits::query::NoSolution;
 use crate::traits::{
-    ChalkEnvironmentAndGoal, ChalkEnvironmentClause, FulfillmentError, FulfillmentErrorCode,
-    ObligationCause, PredicateObligation, SelectionError, TraitEngine,
+    ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause,
+    PredicateObligation, SelectionError, TraitEngine,
 };
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty};
 
 pub struct FulfillmentContext<'tcx> {
     obligations: FxIndexSet<PredicateObligation<'tcx>>,
@@ -21,132 +20,6 @@ impl FulfillmentContext<'tcx> {
     }
 }
 
-fn environment<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-) -> &'tcx ty::List<ChalkEnvironmentClause<'tcx>> {
-    use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind};
-    use rustc_middle::ty::subst::GenericArgKind;
-
-    debug!("environment(def_id = {:?})", def_id);
-
-    // The environment of an impl Trait type is its defining function's environment.
-    if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
-        return environment(tcx, parent);
-    }
-
-    // Compute the bounds on `Self` and the type parameters.
-    let ty::InstantiatedPredicates { predicates, .. } =
-        tcx.predicates_of(def_id).instantiate_identity(tcx);
-
-    let clauses = predicates.into_iter().map(ChalkEnvironmentClause::Predicate);
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-    let node = tcx.hir().get(hir_id);
-
-    enum NodeKind {
-        TraitImpl,
-        InherentImpl,
-        Fn,
-        Other,
-    };
-
-    let node_kind = match node {
-        Node::TraitItem(item) => match item.kind {
-            TraitItemKind::Fn(..) => NodeKind::Fn,
-            _ => NodeKind::Other,
-        },
-
-        Node::ImplItem(item) => match item.kind {
-            ImplItemKind::Fn(..) => NodeKind::Fn,
-            _ => NodeKind::Other,
-        },
-
-        Node::Item(item) => match item.kind {
-            ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl,
-            ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl,
-            ItemKind::Fn(..) => NodeKind::Fn,
-            _ => NodeKind::Other,
-        },
-
-        Node::ForeignItem(item) => match item.kind {
-            ForeignItemKind::Fn(..) => NodeKind::Fn,
-            _ => NodeKind::Other,
-        },
-
-        // FIXME: closures?
-        _ => NodeKind::Other,
-    };
-
-    // FIXME(eddyb) isn't the unordered nature of this a hazard?
-    let mut inputs = FxIndexSet::default();
-
-    match node_kind {
-        // In a trait impl, we assume that the header trait ref and all its
-        // constituents are well-formed.
-        NodeKind::TraitImpl => {
-            let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
-
-            // FIXME(chalk): this has problems because of late-bound regions
-            //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
-            inputs.extend(trait_ref.substs.iter());
-        }
-
-        // In an inherent impl, we assume that the receiver type and all its
-        // constituents are well-formed.
-        NodeKind::InherentImpl => {
-            let self_ty = tcx.type_of(def_id);
-            inputs.extend(self_ty.walk());
-        }
-
-        // In an fn, we assume that the arguments and all their constituents are
-        // well-formed.
-        NodeKind::Fn => {
-            let fn_sig = tcx.fn_sig(def_id);
-            let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig);
-
-            inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
-        }
-
-        NodeKind::Other => (),
-    }
-    let input_clauses = inputs.into_iter().filter_map(|arg| {
-        match arg.unpack() {
-            GenericArgKind::Type(ty) => Some(ChalkEnvironmentClause::TypeFromEnv(ty)),
-
-            // FIXME(eddyb) no WF conditions from lifetimes?
-            GenericArgKind::Lifetime(_) => None,
-
-            // FIXME(eddyb) support const generics in Chalk
-            GenericArgKind::Const(_) => None,
-        }
-    });
-
-    tcx.mk_chalk_environment_clause_list(clauses.chain(input_clauses))
-}
-
-/// We need to wrap a `ty::Predicate` in an elaborated environment *before* we
-/// canonicalize. This is due to the fact that we insert extra clauses into the
-/// environment for all input types (`FromEnv`).
-fn in_environment(
-    infcx: &InferCtxt<'_, 'tcx>,
-    obligation: &PredicateObligation<'tcx>,
-) -> ChalkEnvironmentAndGoal<'tcx> {
-    assert!(!infcx.is_in_snapshot());
-    let obligation = infcx.resolve_vars_if_possible(obligation);
-
-    let environment = match obligation.param_env.def_id {
-        Some(def_id) => environment(infcx.tcx, def_id),
-        None if obligation.param_env.caller_bounds().is_empty() => ty::List::empty(),
-        // FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl
-        // and ui/generics/generic-static-methods
-        //_ => bug!("non-empty `ParamEnv` with no def-id"),
-        _ => ty::List::empty(),
-    };
-
-    ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }
-}
-
 impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
     fn normalize_projection_type(
         &mut self,
@@ -195,6 +68,8 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
     ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+        assert!(!infcx.is_in_snapshot());
+
         let mut errors = Vec::new();
         let mut next_round = FxIndexSet::default();
         let mut making_progress;
@@ -205,10 +80,11 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
             // We iterate over all obligations, and record if we are able
             // to unambiguously prove at least one obligation.
             for obligation in self.obligations.drain(..) {
-                let goal_in_environment = in_environment(infcx, &obligation);
+                let obligation = infcx.resolve_vars_if_possible(&obligation);
+                let environment = obligation.param_env.caller_bounds();
+                let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
                 let mut orig_values = OriginalQueryValues::default();
-                let canonical_goal =
-                    infcx.canonicalize_query(&goal_in_environment, &mut orig_values);
+                let canonical_goal = infcx.canonicalize_query(&goal, &mut orig_values);
 
                 match infcx.tcx.evaluate_goal(canonical_goal) {
                     Ok(response) => {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index dcd83798033..a9651144e59 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -663,6 +663,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             obligation
                         )
                     }
+
+                    ty::PredicateAtom::TypeWellFormedFromEnv(..) => span_bug!(
+                        span,
+                        "TypeWellFormedFromEnv predicate should only exist in the environment"
+                    ),
                 }
             }
 
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 4818022bf62..1dd50d69a21 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -87,7 +87,7 @@ pub struct PendingPredicateObligation<'tcx> {
 
 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(PendingPredicateObligation<'_>, 64);
+static_assert_size!(PendingPredicateObligation<'_>, 56);
 
 impl<'a, 'tcx> FulfillmentContext<'tcx> {
     /// Creates a new fulfillment context.
@@ -355,6 +355,9 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                         obligation.with(pred.to_predicate(self.selcx.tcx())),
                     ]))
                 }
+                ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+                    bug!("TypeWellFormedFromEnv is only used for Chalk")
+                }
             },
             &ty::PredicateKind::Atom(atom) => match atom {
                 ty::PredicateAtom::Trait(ref data, _) => {
@@ -536,6 +539,9 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                         }
                     }
                 }
+                ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+                    bug!("TypeWellFormedFromEnv is only used for Chalk")
+                }
             },
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 49dac873cde..b72e86a4cbd 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -302,11 +302,8 @@ pub fn normalize_param_env_or_error<'tcx>(
 
     debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
 
-    let elaborated_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
-        unnormalized_env.reveal(),
-        unnormalized_env.def_id,
-    );
+    let elaborated_env =
+        ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal());
 
     // HACK: we are trying to normalize the param-env inside *itself*. The problem is that
     // normalization expects its param-env to be already normalized, which means we have
@@ -360,7 +357,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     let outlives_env: Vec<_> =
         non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
     let outlives_env =
-        ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal(), None);
+        ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal());
     let outlives_predicates = match do_normalize_predicates(
         tcx,
         region_context,
@@ -380,11 +377,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     let mut predicates = non_outlives_predicates;
     predicates.extend(outlives_predicates);
     debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
-    ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
-        unnormalized_env.reveal(),
-        unnormalized_env.def_id,
-    )
+    ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal())
 }
 
 pub fn fully_normalize<'a, 'tcx, T>(
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 6c0c33d3dad..2f2ac9f094d 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -276,7 +276,8 @@ fn predicates_reference_self(
                 | ty::PredicateAtom::ClosureKind(..)
                 | ty::PredicateAtom::Subtype(..)
                 | ty::PredicateAtom::ConstEvaluatable(..)
-                | ty::PredicateAtom::ConstEquate(..) => None,
+                | ty::PredicateAtom::ConstEquate(..)
+                | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
             }
         })
         .collect()
@@ -310,7 +311,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
             | ty::PredicateAtom::ClosureKind(..)
             | ty::PredicateAtom::TypeOutlives(..)
             | ty::PredicateAtom::ConstEvaluatable(..)
-            | ty::PredicateAtom::ConstEquate(..) => false,
+            | ty::PredicateAtom::ConstEquate(..)
+            | ty::PredicateAtom::TypeWellFormedFromEnv(..) => false,
         }
     })
 }
@@ -654,11 +656,7 @@ fn receiver_is_dispatchable<'tcx>(
             .chain(iter::once(trait_predicate))
             .collect();
 
-        ty::ParamEnv::new(
-            tcx.intern_predicates(&caller_bounds),
-            param_env.reveal(),
-            param_env.def_id,
-        )
+        ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal())
     };
 
     // Receiver: DispatchFromDyn<Receiver[Self => U]>
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 7e8e2baa8a1..ac98d840e98 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -593,6 +593,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                 }
             }
+            ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+                bug!("TypeWellFormedFromEnv is only used for chalk")
+            }
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index eb9ee2868f9..998990f374c 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -127,6 +127,9 @@ pub fn predicate_obligations<'a, 'tcx>(
             wf.compute(c1.into());
             wf.compute(c2.into());
         }
+        ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+            bug!("TypeWellFormedFromEnv is only used for Chalk")
+        }
     }
 
     wf.normalize()
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index e89a51a8176..650404e8ca6 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -31,9 +31,7 @@
 //! not. To lower anything wrapped in a `Binder`, we first deeply find any bound
 //! variables from the current `Binder`.
 
-use rustc_middle::traits::{
-    ChalkEnvironmentAndGoal, ChalkEnvironmentClause, ChalkRustInterner as RustInterner,
-};
+use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner};
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{
@@ -43,8 +41,6 @@ use rustc_span::def_id::DefId;
 
 use std::collections::btree_map::{BTreeMap, Entry};
 
-use chalk_ir::fold::shift::Shift;
-
 /// Essentially an `Into` with a `&RustInterner` parameter
 crate trait LowerInto<'tcx, T> {
     /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk type, consuming `self`.
@@ -82,60 +78,45 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
         self,
         interner: &RustInterner<'tcx>,
     ) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> {
-        let clauses = self.environment.into_iter().map(|clause| match clause {
-            ChalkEnvironmentClause::Predicate(predicate) => {
-                let (predicate, binders, _named_regions) =
-                    collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx));
-                let consequence = match predicate {
-                    ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv(
-                        chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)),
-                    ),
-                    ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds(
-                        chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
-                            a: predicate.0.lower_into(interner),
-                            b: predicate.1.lower_into(interner),
-                        }),
-                    ),
-                    ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds(
-                        chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
-                            ty: predicate.0.lower_into(interner),
-                            lifetime: predicate.1.lower_into(interner),
-                        }),
-                    ),
-                    ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds(
-                        chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)),
-                    ),
-                    ty::PredicateAtom::WellFormed(..)
-                    | ty::PredicateAtom::ObjectSafe(..)
-                    | ty::PredicateAtom::ClosureKind(..)
-                    | ty::PredicateAtom::Subtype(..)
-                    | ty::PredicateAtom::ConstEvaluatable(..)
-                    | ty::PredicateAtom::ConstEquate(..) => {
-                        bug!("unexpected predicate {}", predicate)
-                    }
-                };
-                let value = chalk_ir::ProgramClauseImplication {
-                    consequence,
-                    conditions: chalk_ir::Goals::empty(interner),
-                    priority: chalk_ir::ClausePriority::High,
-                    constraints: chalk_ir::Constraints::empty(interner),
-                };
-                chalk_ir::ProgramClauseData(chalk_ir::Binders::new(binders, value)).intern(interner)
-            }
-            ChalkEnvironmentClause::TypeFromEnv(ty) => {
-                chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
-                    chalk_ir::VariableKinds::empty(interner),
-                    chalk_ir::ProgramClauseImplication {
-                        consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(
-                            ty.lower_into(interner).shifted_in(interner),
-                        )),
-                        conditions: chalk_ir::Goals::empty(interner),
-                        priority: chalk_ir::ClausePriority::High,
-                        constraints: chalk_ir::Constraints::empty(interner),
-                    },
-                ))
-                .intern(interner)
-            }
+        let clauses = self.environment.into_iter().map(|predicate| {
+            let (predicate, binders, _named_regions) =
+                collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx));
+            let consequence = match predicate {
+                ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+                    chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner)))
+                }
+                ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv(
+                    chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)),
+                ),
+                ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds(
+                    chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
+                        a: predicate.0.lower_into(interner),
+                        b: predicate.1.lower_into(interner),
+                    }),
+                ),
+                ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds(
+                    chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
+                        ty: predicate.0.lower_into(interner),
+                        lifetime: predicate.1.lower_into(interner),
+                    }),
+                ),
+                ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds(
+                    chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)),
+                ),
+                ty::PredicateAtom::WellFormed(..)
+                | ty::PredicateAtom::ObjectSafe(..)
+                | ty::PredicateAtom::ClosureKind(..)
+                | ty::PredicateAtom::Subtype(..)
+                | ty::PredicateAtom::ConstEvaluatable(..)
+                | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
+            };
+            let value = chalk_ir::ProgramClauseImplication {
+                consequence,
+                conditions: chalk_ir::Goals::empty(interner),
+                priority: chalk_ir::ClausePriority::High,
+                constraints: chalk_ir::Constraints::empty(interner),
+            };
+            chalk_ir::ProgramClauseData(chalk_ir::Binders::new(binders, value)).intern(interner)
         });
 
         let goal: chalk_ir::GoalData<RustInterner<'tcx>> = self.goal.lower_into(&interner);
@@ -214,6 +195,9 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
             | ty::PredicateAtom::ConstEquate(..) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
             }
+            ty::PredicateAtom::TypeWellFormedFromEnv(ty) => chalk_ir::GoalData::DomainGoal(
+                chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))),
+            ),
         };
 
         chalk_ir::GoalData::Quantified(
@@ -684,7 +668,10 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             | ty::PredicateAtom::ClosureKind(..)
             | ty::PredicateAtom::Subtype(..)
             | ty::PredicateAtom::ConstEvaluatable(..)
-            | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", &self),
+            | ty::PredicateAtom::ConstEquate(..)
+            | ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+                bug!("unexpected predicate {}", &self)
+            }
         };
         value.map(|value| chalk_ir::Binders::new(binders, value))
     }
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index c0d4a5d0e7e..63c5b884357 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -1,8 +1,7 @@
 //! Calls `chalk-solve` to solve a `ty::Predicate`
 //!
-//! In order to call `chalk-solve`, this file must convert a
-//! `ChalkCanonicalGoal` into a Chalk ucanonical goal. It then calls Chalk, and
-//! converts the answer back into rustc solution.
+//! In order to call `chalk-solve`, this file must convert a `CanonicalChalkEnvironmentAndGoal` into
+//! a Chalk uncanonical goal. It then calls Chalk, and converts the answer back into rustc solution.
 
 crate mod db;
 crate mod lowering;
@@ -20,7 +19,7 @@ use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable};
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
 };
-use rustc_infer::traits::{self, ChalkCanonicalGoal};
+use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal};
 
 use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase;
 use crate::chalk::lowering::{
@@ -35,7 +34,7 @@ crate fn provide(p: &mut Providers) {
 
 crate fn evaluate_goal<'tcx>(
     tcx: TyCtxt<'tcx>,
-    obligation: ChalkCanonicalGoal<'tcx>,
+    obligation: CanonicalChalkEnvironmentAndGoal<'tcx>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> {
     let interner = ChalkRustInterner { tcx };
 
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index de3096eac9b..79308b032ec 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -103,7 +103,8 @@ fn compute_implied_outlives_bounds<'tcx>(
                     | ty::PredicateAtom::ClosureKind(..)
                     | ty::PredicateAtom::ObjectSafe(..)
                     | ty::PredicateAtom::ConstEvaluatable(..)
-                    | ty::PredicateAtom::ConstEquate(..) => vec![],
+                    | ty::PredicateAtom::ConstEquate(..)
+                    | ty::PredicateAtom::TypeWellFormedFromEnv(..) => vec![],
                     ty::PredicateAtom::WellFormed(arg) => {
                         wf_args.push(arg);
                         vec![]
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 83aee31a39f..3e7c9ac62eb 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -49,6 +49,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
         | ty::PredicateAtom::ClosureKind(..)
         | ty::PredicateAtom::Subtype(..)
         | ty::PredicateAtom::ConstEvaluatable(..)
-        | ty::PredicateAtom::ConstEquate(..) => true,
+        | ty::PredicateAtom::ConstEquate(..)
+        | ty::PredicateAtom::TypeWellFormedFromEnv(..) => true,
     }
 }
diff --git a/compiler/rustc_ty/src/ty.rs b/compiler/rustc_ty/src/ty.rs
index a0235444ac4..c4b6b64339a 100644
--- a/compiler/rustc_ty/src/ty.rs
+++ b/compiler/rustc_ty/src/ty.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -5,7 +6,9 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_infer::traits::util;
 use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{
+    self, Binder, Predicate, PredicateAtom, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
+};
 use rustc_session::CrateDisambiguator;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -245,7 +248,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     }
     // Compute the bounds on Self and the type parameters.
 
-    let ty::InstantiatedPredicates { predicates, .. } =
+    let ty::InstantiatedPredicates { mut predicates, .. } =
         tcx.predicates_of(def_id).instantiate_identity(tcx);
 
     // Finally, we have to normalize the bounds in the environment, in
@@ -260,11 +263,13 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     // are any errors at that point, so after type checking you can be
     // sure that this will succeed without errors anyway.
 
-    let unnormalized_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
-        traits::Reveal::UserFacing,
-        tcx.sess.opts.debugging_opts.chalk.then_some(def_id),
-    );
+    if tcx.sess.opts.debugging_opts.chalk {
+        let environment = well_formed_types_in_env(tcx, def_id);
+        predicates.extend(environment);
+    }
+
+    let unnormalized_env =
+        ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
 
     let body_id = def_id
         .as_local()
@@ -276,6 +281,122 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
 }
 
+/// Elaborate the environment.
+///
+/// Collect a list of `Predicate`'s used for building the `ParamEnv`. Adds `TypeWellFormedFromEnv`'s
+/// that are assumed to be well-formed (because they come from the environment).
+///
+/// Used only in chalk mode.
+fn well_formed_types_in_env<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+) -> &'tcx ty::List<Predicate<'tcx>> {
+    use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind};
+    use rustc_middle::ty::subst::GenericArgKind;
+
+    debug!("environment(def_id = {:?})", def_id);
+
+    // The environment of an impl Trait type is its defining function's environment.
+    if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
+        return well_formed_types_in_env(tcx, parent);
+    }
+
+    // Compute the bounds on `Self` and the type parameters.
+    let ty::InstantiatedPredicates { predicates, .. } =
+        tcx.predicates_of(def_id).instantiate_identity(tcx);
+
+    let clauses = predicates.into_iter();
+
+    if !def_id.is_local() {
+        return ty::List::empty();
+    }
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    let node = tcx.hir().get(hir_id);
+
+    enum NodeKind {
+        TraitImpl,
+        InherentImpl,
+        Fn,
+        Other,
+    };
+
+    let node_kind = match node {
+        Node::TraitItem(item) => match item.kind {
+            TraitItemKind::Fn(..) => NodeKind::Fn,
+            _ => NodeKind::Other,
+        },
+
+        Node::ImplItem(item) => match item.kind {
+            ImplItemKind::Fn(..) => NodeKind::Fn,
+            _ => NodeKind::Other,
+        },
+
+        Node::Item(item) => match item.kind {
+            ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl,
+            ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl,
+            ItemKind::Fn(..) => NodeKind::Fn,
+            _ => NodeKind::Other,
+        },
+
+        Node::ForeignItem(item) => match item.kind {
+            ForeignItemKind::Fn(..) => NodeKind::Fn,
+            _ => NodeKind::Other,
+        },
+
+        // FIXME: closures?
+        _ => NodeKind::Other,
+    };
+
+    // FIXME(eddyb) isn't the unordered nature of this a hazard?
+    let mut inputs = FxIndexSet::default();
+
+    match node_kind {
+        // In a trait impl, we assume that the header trait ref and all its
+        // constituents are well-formed.
+        NodeKind::TraitImpl => {
+            let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
+
+            // FIXME(chalk): this has problems because of late-bound regions
+            //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
+            inputs.extend(trait_ref.substs.iter());
+        }
+
+        // In an inherent impl, we assume that the receiver type and all its
+        // constituents are well-formed.
+        NodeKind::InherentImpl => {
+            let self_ty = tcx.type_of(def_id);
+            inputs.extend(self_ty.walk());
+        }
+
+        // In an fn, we assume that the arguments and all their constituents are
+        // well-formed.
+        NodeKind::Fn => {
+            let fn_sig = tcx.fn_sig(def_id);
+            let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig);
+
+            inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
+        }
+
+        NodeKind::Other => (),
+    }
+    let input_clauses = inputs.into_iter().filter_map(|arg| {
+        match arg.unpack() {
+            GenericArgKind::Type(ty) => {
+                let binder = Binder::dummy(PredicateAtom::TypeWellFormedFromEnv(ty));
+                Some(tcx.mk_predicate(PredicateKind::ForAll(binder)))
+            }
+
+            // FIXME(eddyb) no WF conditions from lifetimes?
+            GenericArgKind::Lifetime(_) => None,
+
+            // FIXME(eddyb) support const generics in Chalk
+            GenericArgKind::Const(_) => None,
+        }
+    });
+
+    tcx.mk_predicates(clauses.chain(input_clauses))
+}
+
 fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     tcx.param_env(def_id).with_reveal_all_normalized(tcx)
 }
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index bbf5153d35d..7aa54e0ebcc 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -202,11 +202,8 @@ fn compare_predicate_entailment<'tcx>(
     // The key step here is to update the caller_bounds's predicates to be
     // the new hybrid bounds we computed.
     let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
-    let param_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&hybrid_preds.predicates),
-        Reveal::UserFacing,
-        None,
-    );
+    let param_env =
+        ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
     let param_env = traits::normalize_param_env_or_error(
         tcx,
         impl_m.def_id,
@@ -1120,11 +1117,8 @@ fn compare_type_predicate_entailment<'tcx>(
     debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
 
     let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
-    let param_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&hybrid_preds.predicates),
-        Reveal::UserFacing,
-        None,
-    );
+    let param_env =
+        ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
     let param_env = traits::normalize_param_env_or_error(
         tcx,
         impl_ty.def_id,
@@ -1227,7 +1221,7 @@ fn compare_projection_bounds<'tcx>(
             })
             .to_predicate(tcx),
         );
-        ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing, None)
+        ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
     };
 
     tcx.infer_ctxt().enter(move |infcx| {
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 14d80fded71..ebe71b86c92 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -814,7 +814,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     | ty::PredicateAtom::ClosureKind(..)
                     | ty::PredicateAtom::TypeOutlives(..)
                     | ty::PredicateAtom::ConstEvaluatable(..)
-                    | ty::PredicateAtom::ConstEquate(..) => None,
+                    | ty::PredicateAtom::ConstEquate(..)
+                    | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
                 },
             );
 
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index cb5f5731aa6..b95034adb24 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -3918,6 +3918,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // code is looking for a self type of a unresolved
                     // inference variable.
                     ty::PredicateAtom::ClosureKind(..) => None,
+                    ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
                 }
             })
             .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
index 3746e5778aa..60b9467fca8 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -405,6 +405,7 @@ fn trait_predicate_kind<'tcx>(
         | ty::PredicateAtom::ObjectSafe(_)
         | ty::PredicateAtom::ClosureKind(..)
         | ty::PredicateAtom::ConstEvaluatable(..)
-        | ty::PredicateAtom::ConstEquate(..) => None,
+        | ty::PredicateAtom::ConstEquate(..)
+        | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
     }
 }
diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs
index 135960a4c11..ae336ccca45 100644
--- a/compiler/rustc_typeck/src/outlives/explicit.rs
+++ b/compiler/rustc_typeck/src/outlives/explicit.rs
@@ -57,7 +57,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
                     | ty::PredicateAtom::ClosureKind(..)
                     | ty::PredicateAtom::Subtype(..)
                     | ty::PredicateAtom::ConstEvaluatable(..)
-                    | ty::PredicateAtom::ConstEquate(..) => (),
+                    | ty::PredicateAtom::ConstEquate(..)
+                    | ty::PredicateAtom::TypeWellFormedFromEnv(..) => (),
                 }
             }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7385cccbe95..6a75a9bfb74 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -508,7 +508,8 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
             | ty::PredicateAtom::ObjectSafe(..)
             | ty::PredicateAtom::ClosureKind(..)
             | ty::PredicateAtom::ConstEvaluatable(..)
-            | ty::PredicateAtom::ConstEquate(..) => panic!("not user writable"),
+            | ty::PredicateAtom::ConstEquate(..)
+            | ty::PredicateAtom::TypeWellFormedFromEnv(..) => panic!("not user writable"),
         }
     }
 }
diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr
index fb8ccbfc660..91c46b95315 100644
--- a/src/test/ui/chalkify/type_inference.stderr
+++ b/src/test/ui/chalkify/type_inference.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `{float}: Bar` is not satisfied
-  --> $DIR/type_inference.rs:27:5
+  --> $DIR/type_inference.rs:27:14
    |
 LL | fn only_bar<T: Bar>(_x: T) { }
    |                --- required by this bound in `only_bar`
 ...
 LL |     only_bar(x);
-   |     ^^^^^^^^ the trait `Bar` is not implemented for `{float}`
+   |              ^ the trait `Bar` is not implemented for `{float}`
    |
    = help: the following implementations were found:
              <i32 as Bar>
diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr
index 6d1df4fda2e..45322ea9672 100644
--- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr
+++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr
@@ -18,7 +18,7 @@ LL | enum MList { Cons(isize, MList), Nil }
    | ^^^^^^^^^^
    |
    = note: ...which again requires computing drop-check constraints for `MList`, completing the cycle
-   = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, value: MList } }`
+   = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: MList } }`
 
 error: aborting due to 2 previous errors