about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock49
-rw-r--r--src/librustc_middle/Cargo.toml2
-rw-r--r--src/librustc_middle/traits/chalk.rs2
-rw-r--r--src/librustc_trait_selection/traits/chalk_fulfill.rs15
-rw-r--r--src/librustc_traits/Cargo.toml4
-rw-r--r--src/librustc_traits/chalk/db.rs180
-rw-r--r--src/librustc_traits/chalk/lowering.rs42
-rw-r--r--src/librustc_traits/chalk/mod.rs1
-rw-r--r--src/test/ui/chalkify/closure.rs39
-rw-r--r--src/test/ui/chalkify/closure.stderr18
-rw-r--r--src/test/ui/chalkify/impl_wf.rs7
-rw-r--r--src/test/ui/chalkify/impl_wf.stderr15
-rw-r--r--src/test/ui/chalkify/inherent_impl.rs17
-rw-r--r--src/test/ui/chalkify/recursive_where_clause_on_type.rs11
-rw-r--r--src/test/ui/chalkify/recursive_where_clause_on_type.stderr16
15 files changed, 311 insertions, 107 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 8a0991059d5..8cbf6cf6869 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -434,9 +434,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-derive"
-version = "0.11.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b9bd01eab87277d973183a1d2e56bace1c11f8242c52c20636fb7dddf343ac9"
+checksum = "d463e01905d607e181de72e8608721d3269f29176c9a14ce037011316ae7131d"
 dependencies = [
  "proc-macro2 1.0.3",
  "quote 1.0.2",
@@ -446,20 +446,21 @@ dependencies = [
 
 [[package]]
 name = "chalk-engine"
-version = "0.11.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c7a637c3d17ed555aef16e16952a5d1e127bd55178cc30be22afeb92da90c7d"
+checksum = "efaf428f5398d36284f79690cf988762b7c091249f50a6c11db613a46c057000"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
  "rustc-hash",
+ "tracing",
 ]
 
 [[package]]
 name = "chalk-ir"
-version = "0.11.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "595e5735ded16c3f3dc348f7b15bbb2521a0080b1863cac38ad5271589944670"
+checksum = "fd3fdc1e9f68498ffe80f4a23b0b95f1ca6fb21d5a4c9b0c085fab3ca712bdbe"
 dependencies = [
  "chalk-derive",
  "lazy_static",
@@ -467,9 +468,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.11.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d9d938139db425867a30cc0cfec0269406d8238d0571d829041eaa7a8455d11"
+checksum = "5b9fd4102807b7ebe8fb034fa0f488c5656e1966d3261b558b81a08d519cdb29"
 dependencies = [
  "chalk-derive",
  "chalk-engine",
@@ -478,6 +479,7 @@ dependencies = [
  "itertools 0.9.0",
  "petgraph",
  "rustc-hash",
+ "tracing",
 ]
 
 [[package]]
@@ -5333,6 +5335,37 @@ dependencies = [
 ]
 
 [[package]]
+name = "tracing"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a41f40ed0e162c911ac6fcb53ecdc8134c46905fdbbae8c50add462a538b495f"
+dependencies = [
+ "cfg-if",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99bbad0de3fd923c9c3232ead88510b783e5a4d16a6154adffa3d53308de984c"
+dependencies = [
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "syn 1.0.11",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
 name = "try-lock"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/librustc_middle/Cargo.toml b/src/librustc_middle/Cargo.toml
index 21d0b102a4a..02d82c67933 100644
--- a/src/librustc_middle/Cargo.toml
+++ b/src/librustc_middle/Cargo.toml
@@ -30,7 +30,7 @@ rustc_serialize = { path = "../librustc_serialize" }
 rustc_ast = { path = "../librustc_ast" }
 rustc_span = { path = "../librustc_span" }
 byteorder = { version = "1.3" }
-chalk-ir = "0.11.0"
+chalk-ir = "0.14.0"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 measureme = "0.7.1"
 rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc_middle/traits/chalk.rs b/src/librustc_middle/traits/chalk.rs
index a49a0045812..405af8cb240 100644
--- a/src/librustc_middle/traits/chalk.rs
+++ b/src/librustc_middle/traits/chalk.rs
@@ -10,6 +10,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 
 use rustc_hir::def_id::DefId;
+use rustc_target::spec::abi::Abi;
 
 use smallvec::SmallVec;
 
@@ -77,6 +78,7 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> {
     type DefId = DefId;
     type InternedAdtId = &'tcx AdtDef;
     type Identifier = ();
+    type FnAbi = Abi;
 
     fn debug_program_clause_implication(
         pci: &chalk_ir::ProgramClauseImplication<Self>,
diff --git a/src/librustc_trait_selection/traits/chalk_fulfill.rs b/src/librustc_trait_selection/traits/chalk_fulfill.rs
index cbbff82d35f..2ade4892752 100644
--- a/src/librustc_trait_selection/traits/chalk_fulfill.rs
+++ b/src/librustc_trait_selection/traits/chalk_fulfill.rs
@@ -7,17 +7,17 @@ use crate::traits::{
     ChalkEnvironmentAndGoal, ChalkEnvironmentClause, FulfillmentError, FulfillmentErrorCode,
     ObligationCause, PredicateObligation, SelectionError, TraitEngine,
 };
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 pub struct FulfillmentContext<'tcx> {
-    obligations: FxHashSet<PredicateObligation<'tcx>>,
+    obligations: FxIndexSet<PredicateObligation<'tcx>>,
 }
 
 impl FulfillmentContext<'tcx> {
     crate fn new() -> Self {
-        FulfillmentContext { obligations: FxHashSet::default() }
+        FulfillmentContext { obligations: FxIndexSet::default() }
     }
 }
 
@@ -79,7 +79,7 @@ fn environment<'tcx>(
     };
 
     // FIXME(eddyb) isn't the unordered nature of this a hazard?
-    let mut inputs = FxHashSet::default();
+    let mut inputs = FxIndexSet::default();
 
     match node_kind {
         // In a trait impl, we assume that the header trait ref and all its
@@ -140,7 +140,8 @@ fn in_environment(
         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"),
+        //_ => bug!("non-empty `ParamEnv` with no def-id"),
+        _ => ty::List::empty(),
     };
 
     ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }
@@ -195,7 +196,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         infcx: &InferCtxt<'_, 'tcx>,
     ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
         let mut errors = Vec::new();
-        let mut next_round = FxHashSet::default();
+        let mut next_round = FxIndexSet::default();
         let mut making_progress;
 
         loop {
@@ -203,7 +204,7 @@ 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() {
+            for obligation in self.obligations.drain(..) {
                 let goal_in_environment = in_environment(infcx, &obligation);
                 let mut orig_values = OriginalQueryValues::default();
                 let canonical_goal =
diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml
index 8def98a9603..079b9b10fd0 100644
--- a/src/librustc_traits/Cargo.toml
+++ b/src/librustc_traits/Cargo.toml
@@ -16,8 +16,8 @@ rustc_hir = { path = "../librustc_hir" }
 rustc_index = { path = "../librustc_index" }
 rustc_ast = { path = "../librustc_ast" }
 rustc_span = { path = "../librustc_span" }
-chalk-ir = "0.11.0"
-chalk-solve = "0.11.0"
+chalk-ir = "0.14.0"
+chalk-solve = "0.14.0"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 rustc_infer = { path = "../librustc_infer" }
 rustc_trait_selection = { path = "../librustc_trait_selection" }
diff --git a/src/librustc_traits/chalk/db.rs b/src/librustc_traits/chalk/db.rs
index 235497d3740..715e5299a37 100644
--- a/src/librustc_traits/chalk/db.rs
+++ b/src/librustc_traits/chalk/db.rs
@@ -8,7 +8,7 @@
 
 use rustc_middle::traits::ChalkRustInterner as RustInterner;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, AssocItemContainer, AssocKind, Binder, TyCtxt};
+use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt};
 
 use rustc_hir::def_id::DefId;
 
@@ -85,14 +85,29 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
             .iter()
             .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
+        let associated_ty_ids: Vec<_> = self
+            .tcx
+            .associated_items(def_id)
+            .in_definition_order()
+            .filter(|i| i.kind == AssocKind::Type)
+            .map(|i| chalk_ir::AssocTypeId(i.def_id))
+            .collect();
 
         let well_known =
             if self.tcx.lang_items().sized_trait().map(|t| def_id == t).unwrap_or(false) {
-                Some(chalk_solve::rust_ir::WellKnownTrait::SizedTrait)
+                Some(chalk_solve::rust_ir::WellKnownTrait::Sized)
             } else if self.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false) {
-                Some(chalk_solve::rust_ir::WellKnownTrait::CopyTrait)
+                Some(chalk_solve::rust_ir::WellKnownTrait::Copy)
             } else if self.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false) {
-                Some(chalk_solve::rust_ir::WellKnownTrait::CloneTrait)
+                Some(chalk_solve::rust_ir::WellKnownTrait::Clone)
+            } else if self.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false) {
+                Some(chalk_solve::rust_ir::WellKnownTrait::Drop)
+            } else if self.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) {
+                Some(chalk_solve::rust_ir::WellKnownTrait::Fn)
+            } else if self.tcx.lang_items().fn_once_trait().map(|t| def_id == t).unwrap_or(false) {
+                Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce)
+            } else if self.tcx.lang_items().fn_mut_trait().map(|t| def_id == t).unwrap_or(false) {
+                Some(chalk_solve::rust_ir::WellKnownTrait::FnMut)
             } else {
                 None
             };
@@ -110,7 +125,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                 non_enumerable: true,
                 coinductive: false,
             },
-            associated_ty_ids: vec![],
+            associated_ty_ids,
             well_known,
         })
     }
@@ -156,6 +171,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
             flags: chalk_solve::rust_ir::AdtFlags {
                 upstream: !adt_def.did.is_local(),
                 fundamental: adt_def.is_fundamental(),
+                phantom_data: adt_def.is_phantom_data(),
             },
         });
         return struct_datum;
@@ -176,28 +192,32 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
 
         let sig = self.tcx.fn_sig(def_id);
-        // FIXME(chalk): collect into an intermediate SmallVec here since
-        // we need `TypeFoldable` for `no_bound_vars`
-        let argument_types: Binder<Vec<_>> =
-            sig.map_bound(|i| i.inputs().iter().copied().collect());
-        let argument_types = argument_types
-            .no_bound_vars()
-            .expect("FIXME(chalk): late-bound fn parameters not supported in chalk")
+        let inputs_and_output = sig.inputs_and_output();
+        let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars(
+            &self.interner,
+            self.tcx,
+            &inputs_and_output,
+        );
+
+        let argument_types = inputs_and_output[..inputs_and_output.len() - 1]
             .iter()
             .map(|t| t.subst(self.tcx, &bound_vars).lower_into(&self.interner))
             .collect();
 
-        let return_type = sig
-            .output()
-            .no_bound_vars()
-            .expect("FIXME(chalk): late-bound fn parameters not supported in chalk")
+        let return_type = inputs_and_output[inputs_and_output.len() - 1]
             .subst(self.tcx, &bound_vars)
             .lower_into(&self.interner);
 
-        let bound =
-            chalk_solve::rust_ir::FnDefDatumBound { argument_types, where_clauses, return_type };
+        let bound = chalk_solve::rust_ir::FnDefDatumBound {
+            inputs_and_output: chalk_ir::Binders::new(
+                iobinders,
+                chalk_solve::rust_ir::FnDefInputsAndOutputDatum { argument_types, return_type },
+            ),
+            where_clauses,
+        };
         Arc::new(chalk_solve::rust_ir::FnDefDatum {
             id: fn_def_id,
+            abi: sig.abi(),
             binders: chalk_ir::Binders::new(binders, bound),
         })
     }
@@ -326,9 +346,16 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         &self,
         opaque_ty_id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
     ) -> Arc<chalk_solve::rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> {
-        // FIXME(chalk): actually lower opaque ty
+        let bound_vars = bound_vars_for_item(self.tcx, opaque_ty_id.0);
+        let binders = binders_for(&self.interner, bound_vars);
+        let predicates = self.tcx.predicates_defined_on(opaque_ty_id.0).predicates;
+        let where_clauses: Vec<_> = predicates
+            .iter()
+            .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
+            .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
+
         let value = chalk_solve::rust_ir::OpaqueTyDatumBound {
-            bounds: chalk_ir::Binders::new(chalk_ir::VariableKinds::new(&self.interner), vec![]),
+            bounds: chalk_ir::Binders::new(binders, where_clauses),
         };
         Arc::new(chalk_solve::rust_ir::OpaqueTyDatum {
             opaque_ty_id,
@@ -346,7 +373,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
     ) -> Option<bool> {
         use chalk_ir::TyData::*;
         match well_known {
-            chalk_solve::rust_ir::WellKnownTrait::SizedTrait => match ty {
+            chalk_solve::rust_ir::WellKnownTrait::Sized => match ty {
                 Apply(apply) => match apply.name {
                     chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() {
                         ty::AdtKind::Struct | ty::AdtKind::Union => None,
@@ -364,8 +391,8 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                 | InferenceVar(_, _)
                 | BoundVar(_) => None,
             },
-            chalk_solve::rust_ir::WellKnownTrait::CopyTrait
-            | chalk_solve::rust_ir::WellKnownTrait::CloneTrait => match ty {
+            chalk_solve::rust_ir::WellKnownTrait::Copy
+            | chalk_solve::rust_ir::WellKnownTrait::Clone => match ty {
                 Apply(apply) => match apply.name {
                     chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() {
                         ty::AdtKind::Struct | ty::AdtKind::Union => None,
@@ -383,7 +410,11 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                 | InferenceVar(_, _)
                 | BoundVar(_) => None,
             },
-            chalk_solve::rust_ir::WellKnownTrait::DropTrait => None,
+            chalk_solve::rust_ir::WellKnownTrait::Drop => None,
+            chalk_solve::rust_ir::WellKnownTrait::Fn => None,
+            chalk_solve::rust_ir::WellKnownTrait::FnMut => None,
+            chalk_solve::rust_ir::WellKnownTrait::FnOnce => None,
+            chalk_solve::rust_ir::WellKnownTrait::Unsize => None,
         }
     }
 
@@ -399,17 +430,17 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         well_known_trait: chalk_solve::rust_ir::WellKnownTrait,
     ) -> Option<chalk_ir::TraitId<RustInterner<'tcx>>> {
         use chalk_solve::rust_ir::WellKnownTrait::*;
-        let t = match well_known_trait {
-            SizedTrait => {
-                self.tcx.lang_items().sized_trait().map(|t| chalk_ir::TraitId(t)).unwrap()
-            }
-            CopyTrait => self.tcx.lang_items().copy_trait().map(|t| chalk_ir::TraitId(t)).unwrap(),
-            CloneTrait => {
-                self.tcx.lang_items().clone_trait().map(|t| chalk_ir::TraitId(t)).unwrap()
-            }
-            DropTrait => self.tcx.lang_items().drop_trait().map(|t| chalk_ir::TraitId(t)).unwrap(),
+        let def_id = match well_known_trait {
+            Sized => self.tcx.lang_items().sized_trait(),
+            Copy => self.tcx.lang_items().copy_trait(),
+            Clone => self.tcx.lang_items().clone_trait(),
+            Drop => self.tcx.lang_items().drop_trait(),
+            Fn => self.tcx.lang_items().fn_trait(),
+            FnMut => self.tcx.lang_items().fn_mut_trait(),
+            FnOnce => self.tcx.lang_items().fn_once_trait(),
+            Unsize => self.tcx.lang_items().unsize_trait(),
         };
-        Some(t)
+        def_id.map(|t| chalk_ir::TraitId(t))
     }
 
     fn is_object_safe(&self, trait_id: chalk_ir::TraitId<RustInterner<'tcx>>) -> bool {
@@ -423,6 +454,87 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         // FIXME(chalk): actually get hidden ty
         self.tcx.mk_ty(ty::Tuple(self.tcx.intern_substs(&[]))).lower_into(&self.interner)
     }
+
+    fn closure_kind(
+        &self,
+        _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+        substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+    ) -> chalk_solve::rust_ir::ClosureKind {
+        let kind = &substs.parameters(&self.interner)[substs.len(&self.interner) - 3];
+        match kind.assert_ty_ref(&self.interner).data(&self.interner) {
+            chalk_ir::TyData::Apply(apply) => match apply.name {
+                chalk_ir::TypeName::Scalar(scalar) => match scalar {
+                    chalk_ir::Scalar::Int(int_ty) => match int_ty {
+                        chalk_ir::IntTy::I8 => chalk_solve::rust_ir::ClosureKind::Fn,
+                        chalk_ir::IntTy::I16 => chalk_solve::rust_ir::ClosureKind::FnMut,
+                        chalk_ir::IntTy::I32 => chalk_solve::rust_ir::ClosureKind::FnOnce,
+                        _ => bug!("bad closure kind"),
+                    },
+                    _ => bug!("bad closure kind"),
+                },
+                _ => bug!("bad closure kind"),
+            },
+            _ => bug!("bad closure kind"),
+        }
+    }
+
+    fn closure_inputs_and_output(
+        &self,
+        _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+        substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+    ) -> chalk_ir::Binders<chalk_solve::rust_ir::FnDefInputsAndOutputDatum<RustInterner<'tcx>>>
+    {
+        let sig = &substs.parameters(&self.interner)[substs.len(&self.interner) - 2];
+        match sig.assert_ty_ref(&self.interner).data(&self.interner) {
+            chalk_ir::TyData::Function(f) => {
+                let substitution = f.substitution.parameters(&self.interner);
+                let return_type =
+                    substitution.last().unwrap().assert_ty_ref(&self.interner).clone();
+                // Closure arguments are tupled
+                let argument_tuple = substitution[0].assert_ty_ref(&self.interner);
+                let argument_types = match argument_tuple.data(&self.interner) {
+                    chalk_ir::TyData::Apply(apply) => match apply.name {
+                        chalk_ir::TypeName::Tuple(_) => apply
+                            .substitution
+                            .iter(&self.interner)
+                            .map(|arg| arg.assert_ty_ref(&self.interner))
+                            .cloned()
+                            .collect(),
+                        _ => bug!("Expecting closure FnSig args to be tupled."),
+                    },
+                    _ => bug!("Expecting closure FnSig args to be tupled."),
+                };
+
+                chalk_ir::Binders::new(
+                    chalk_ir::VariableKinds::from(
+                        &self.interner,
+                        (0..f.num_binders).map(|_| chalk_ir::VariableKind::Lifetime),
+                    ),
+                    chalk_solve::rust_ir::FnDefInputsAndOutputDatum { argument_types, return_type },
+                )
+            }
+            _ => panic!("Invalid sig."),
+        }
+    }
+
+    fn closure_upvars(
+        &self,
+        _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+        substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+    ) -> chalk_ir::Binders<chalk_ir::Ty<RustInterner<'tcx>>> {
+        let inputs_and_output = self.closure_inputs_and_output(_closure_id, substs);
+        let tuple = substs.parameters(&self.interner).last().unwrap().assert_ty_ref(&self.interner);
+        inputs_and_output.map_ref(|_| tuple.clone())
+    }
+
+    fn closure_fn_substitution(
+        &self,
+        _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+        substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+    ) -> chalk_ir::Substitution<RustInterner<'tcx>> {
+        let substitution = &substs.parameters(&self.interner)[0..substs.len(&self.interner) - 3];
+        chalk_ir::Substitution::from(&self.interner, substitution)
+    }
 }
 
 /// Creates a `InternalSubsts` that maps each generic parameter to a higher-ranked
diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs
index 5546a8db533..e09359b8b3f 100644
--- a/src/librustc_traits/chalk/lowering.rs
+++ b/src/librustc_traits/chalk/lowering.rs
@@ -43,6 +43,8 @@ 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,7 +84,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                             collect_bound_vars(interner, interner.tcx, predicate);
 
                         Some(
-                            chalk_ir::ProgramClauseData::ForAll(chalk_ir::Binders::new(
+                            chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
                                 binders,
                                 chalk_ir::ProgramClauseImplication {
                                     consequence: chalk_ir::DomainGoal::FromEnv(
@@ -102,7 +104,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                             collect_bound_vars(interner, interner.tcx, predicate);
 
                         Some(
-                            chalk_ir::ProgramClauseData::ForAll(chalk_ir::Binders::new(
+                            chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
                                 binders,
                                 chalk_ir::ProgramClauseImplication {
                                     consequence: chalk_ir::DomainGoal::Holds(
@@ -127,7 +129,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                             collect_bound_vars(interner, interner.tcx, predicate);
 
                         Some(
-                            chalk_ir::ProgramClauseData::ForAll(chalk_ir::Binders::new(
+                            chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
                                 binders,
                                 chalk_ir::ProgramClauseImplication {
                                     consequence: chalk_ir::DomainGoal::Holds(
@@ -153,13 +155,16 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                 }
             }
             ChalkEnvironmentClause::TypeFromEnv(ty) => Some(
-                chalk_ir::ProgramClauseData::Implies(chalk_ir::ProgramClauseImplication {
-                    consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(
-                        ty.lower_into(interner),
-                    )),
-                    conditions: chalk_ir::Goals::new(interner),
-                    priority: chalk_ir::ClausePriority::High,
-                })
+                chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
+                    chalk_ir::VariableKinds::new(interner),
+                    chalk_ir::ProgramClauseImplication {
+                        consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(
+                            ty.lower_into(interner).shifted_in(interner),
+                        )),
+                        conditions: chalk_ir::Goals::new(interner),
+                        priority: chalk_ir::ClausePriority::High,
+                    },
+                ))
                 .intern(interner),
             ),
         });
@@ -416,12 +421,15 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
                 })
                 .intern(interner)
             }
-            // FIXME(chalk): add region
-            Dynamic(predicates, _region) => {
-                TyData::Dyn(chalk_ir::DynTy { bounds: predicates.lower_into(interner) })
-                    .intern(interner)
-            }
-            Closure(_def_id, _) => unimplemented!(),
+            Dynamic(predicates, region) => TyData::Dyn(chalk_ir::DynTy {
+                bounds: predicates.lower_into(interner),
+                lifetime: region.lower_into(interner),
+            })
+            .intern(interner),
+            Closure(def_id, substs) => apply(
+                chalk_ir::TypeName::Closure(chalk_ir::ClosureId(def_id)),
+                substs.lower_into(interner),
+            ),
             Generator(_def_id, _substs, _) => unimplemented!(),
             GeneratorWitness(_) => unimplemented!(),
             Never => apply(chalk_ir::TypeName::Never, empty()),
@@ -624,7 +632,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>(
     }
 
     (0..parameters.len()).for_each(|i| {
-        parameters.get(&(i as u32)).expect("Skipped bound var index.");
+        parameters.get(&(i as u32)).expect(&format!("Skipped bound var index `{:?}`.", i));
     });
 
     let binders = chalk_ir::VariableKinds::from(interner, parameters.into_iter().map(|(_, v)| v));
diff --git a/src/librustc_traits/chalk/mod.rs b/src/librustc_traits/chalk/mod.rs
index 6f657be0908..52ec0f2409d 100644
--- a/src/librustc_traits/chalk/mod.rs
+++ b/src/librustc_traits/chalk/mod.rs
@@ -133,6 +133,7 @@ crate fn evaluate_goal<'tcx>(
                             },
                             chalk_ir::TypeName::Array => unimplemented!(),
                             chalk_ir::TypeName::FnDef(_) => unimplemented!(),
+                            chalk_ir::TypeName::Closure(_) => unimplemented!(),
                             chalk_ir::TypeName::Never => unimplemented!(),
                             chalk_ir::TypeName::Tuple(_size) => unimplemented!(),
                             chalk_ir::TypeName::Slice => unimplemented!(),
diff --git a/src/test/ui/chalkify/closure.rs b/src/test/ui/chalkify/closure.rs
new file mode 100644
index 00000000000..81114d491d7
--- /dev/null
+++ b/src/test/ui/chalkify/closure.rs
@@ -0,0 +1,39 @@
+// check-fail
+// compile-flags: -Z chalk
+
+fn main() -> () {
+    let t = || {};
+    t();
+
+    let mut a = 0;
+    let mut b = move || {
+        a = 1;
+    };
+    b();
+
+    let mut c = b;
+
+    c();
+    b();
+
+    let mut a = 0;
+    let mut b = || {
+        a = 1;
+    };
+    b();
+
+    let mut c = b;
+
+    c();
+    b(); //~ ERROR
+
+    // FIXME(chalk): this doesn't quite work
+    /*
+    let b = |c| {
+        c
+    };
+
+    let a = &32;
+    b(a);
+    */
+}
diff --git a/src/test/ui/chalkify/closure.stderr b/src/test/ui/chalkify/closure.stderr
new file mode 100644
index 00000000000..d5a48a7dc6f
--- /dev/null
+++ b/src/test/ui/chalkify/closure.stderr
@@ -0,0 +1,18 @@
+error[E0382]: borrow of moved value: `b`
+  --> $DIR/closure.rs:28:5
+   |
+LL |     let mut c = b;
+   |                 - value moved here
+...
+LL |     b();
+   |     ^ value borrowed here after move
+   |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment
+  --> $DIR/closure.rs:21:9
+   |
+LL |         a = 1;
+   |         ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/chalkify/impl_wf.rs b/src/test/ui/chalkify/impl_wf.rs
index fdc94f69bf2..465eb10241e 100644
--- a/src/test/ui/chalkify/impl_wf.rs
+++ b/src/test/ui/chalkify/impl_wf.rs
@@ -23,15 +23,10 @@ impl<T> Bar for Option<T> {
     type Item = Option<T>;
 }
 
-// FIXME(chalk): the ordering of these two errors differs between CI and local
-// We need to figure out why its non-deterministic
-/*
 impl Bar for f32 {
-//^ ERROR the trait bound `f32: Foo` is not satisfied
     type Item = f32;
-    //^ ERROR the trait bound `f32: Foo` is not satisfied
+    //~^ ERROR the trait bound `f32: Foo` is not satisfied
 }
-*/
 
 trait Baz<U: ?Sized> where U: Foo { }
 
diff --git a/src/test/ui/chalkify/impl_wf.stderr b/src/test/ui/chalkify/impl_wf.stderr
index 5293bbaecd3..e5d7615e43e 100644
--- a/src/test/ui/chalkify/impl_wf.stderr
+++ b/src/test/ui/chalkify/impl_wf.stderr
@@ -11,7 +11,18 @@ LL | impl Foo for str { }
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the trait bound `f32: Foo` is not satisfied
-  --> $DIR/impl_wf.rs:40:6
+  --> $DIR/impl_wf.rs:27:17
+   |
+LL | trait Bar {
+   |       --- required by a bound in this
+LL |     type Item: Foo;
+   |                --- required by this bound in `Bar`
+...
+LL |     type Item = f32;
+   |                 ^^^ the trait `Foo` is not implemented for `f32`
+
+error[E0277]: the trait bound `f32: Foo` is not satisfied
+  --> $DIR/impl_wf.rs:35:6
    |
 LL | trait Baz<U: ?Sized> where U: Foo { }
    |                               --- required by this bound in `Baz`
@@ -19,6 +30,6 @@ LL | trait Baz<U: ?Sized> where U: Foo { }
 LL | impl Baz<f32> for f32 { }
    |      ^^^^^^^^ the trait `Foo` is not implemented for `f32`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/chalkify/inherent_impl.rs b/src/test/ui/chalkify/inherent_impl.rs
index 9dd9eb320dd..a2730219fbe 100644
--- a/src/test/ui/chalkify/inherent_impl.rs
+++ b/src/test/ui/chalkify/inherent_impl.rs
@@ -1,7 +1,5 @@
 // run-pass
 // compile-flags: -Z chalk
-// FIXME(chalk): remove when uncommented
-#![allow(dead_code, unused_variables)]
 
 trait Foo { }
 
@@ -11,8 +9,6 @@ struct S<T: Foo> {
     x: T,
 }
 
-// FIXME(chalk): need late-bound regions on FnDefs
-/*
 fn only_foo<T: Foo>(_x: &T) { }
 
 impl<T> S<T> {
@@ -21,7 +17,6 @@ impl<T> S<T> {
         only_foo(&self.x)
     }
 }
-*/
 
 trait Bar { }
 impl Bar for u32 { }
@@ -31,16 +26,10 @@ fn only_bar<T: Bar>() { }
 impl<T> S<T> {
     // Test that the environment of `dummy_bar` adds up with the environment
     // of the inherent impl.
-    // FIXME(chalk): need late-bound regions on FnDefs
-    /*
     fn dummy_bar<U: Bar>(&self) {
         only_foo(&self.x);
         only_bar::<U>();
     }
-    */
-    fn dummy_bar<U: Bar>() {
-        only_bar::<U>();
-    }
 }
 
 fn main() {
@@ -48,10 +37,6 @@ fn main() {
         x: 5,
     };
 
-    // FIXME(chalk): need late-bound regions on FnDefs
-    /*
-    s.dummy_foo();
     s.dummy_bar::<u32>();
-    */
-    S::<i32>::dummy_bar::<u32>();
+    s.dummy_foo();
 }
diff --git a/src/test/ui/chalkify/recursive_where_clause_on_type.rs b/src/test/ui/chalkify/recursive_where_clause_on_type.rs
index 6ee13f5e7a1..87324a5f79b 100644
--- a/src/test/ui/chalkify/recursive_where_clause_on_type.rs
+++ b/src/test/ui/chalkify/recursive_where_clause_on_type.rs
@@ -1,5 +1,5 @@
 // FIXME(chalk): should fail, see comments
-// check-pass
+// check-fail
 // compile-flags: -Z chalk
 
 #![feature(trivial_bounds)]
@@ -10,7 +10,6 @@ trait Bar {
 trait Foo: Bar { }
 
 struct S where S: Foo;
-//~^ WARN Trait bound S: Foo does not depend on any type or lifetime parameters
 
 impl Foo for S {
 }
@@ -26,10 +25,6 @@ fn foo<T: Foo>() {
 fn main() {
     // For some reason, the error is duplicated...
 
-    // FIXME(chalk): this order of this duplicate error seems non-determistic
-    // and causes test to fail
-    /*
-    foo::<S>() // ERROR the type `S` is not well-formed (chalk)
-    //^ ERROR the type `S` is not well-formed (chalk)
-    */
+    foo::<S>() //~ ERROR the type `S` is not well-formed (chalk)
+    //~^ ERROR the type `S` is not well-formed (chalk)
 }
diff --git a/src/test/ui/chalkify/recursive_where_clause_on_type.stderr b/src/test/ui/chalkify/recursive_where_clause_on_type.stderr
index a5b7ef7fdb2..fddd5895927 100644
--- a/src/test/ui/chalkify/recursive_where_clause_on_type.stderr
+++ b/src/test/ui/chalkify/recursive_where_clause_on_type.stderr
@@ -1,10 +1,14 @@
-warning: Trait bound S: Foo does not depend on any type or lifetime parameters
-  --> $DIR/recursive_where_clause_on_type.rs:12:19
+error: the type `S` is not well-formed (chalk)
+  --> $DIR/recursive_where_clause_on_type.rs:28:11
    |
-LL | struct S where S: Foo;
-   |                   ^^^
+LL |     foo::<S>()
+   |           ^
+
+error: the type `S` is not well-formed (chalk)
+  --> $DIR/recursive_where_clause_on_type.rs:28:5
    |
-   = note: `#[warn(trivial_bounds)]` on by default
+LL |     foo::<S>()
+   |     ^^^^^^^^
 
-warning: 1 warning emitted
+error: aborting due to 2 previous errors