diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index f51a3e71d0741..dd2c41dda6403 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1297,7 +1297,7 @@ impl_stable_hash_for!(enum infer::canonical::CanonicalTyVarKind {
 });
 
 impl_stable_hash_for!(
-    impl<'tcx, R> for struct infer::canonical::QueryResult<'tcx, R> {
+    impl<'tcx, R> for struct infer::canonical::QueryResponse<'tcx, R> {
         var_values, region_constraints, certainty, value
     }
 );
diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs
index 1119c928a89ae..8c87c2a01c04f 100644
--- a/src/librustc/infer/canonical/canonicalizer.rs
+++ b/src/librustc/infer/canonical/canonicalizer.rs
@@ -17,7 +17,7 @@
 
 use infer::canonical::{
     Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized,
-    SmallCanonicalVarValues,
+    OriginalQueryValues,
 };
 use infer::InferCtxt;
 use std::sync::atomic::Ordering;
@@ -48,7 +48,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     pub fn canonicalize_query<V>(
         &self,
         value: &V,
-        var_values: &mut SmallCanonicalVarValues<'tcx>
+        query_state: &mut OriginalQueryValues<'tcx>,
     ) -> Canonicalized<'gcx, V>
     where
         V: TypeFoldable<'tcx> + Lift<'gcx>,
@@ -63,11 +63,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
             value,
             Some(self),
             self.tcx,
-            CanonicalizeRegionMode {
-                static_region: true,
-                other_free_regions: true,
-            },
-            var_values,
+            &CanonicalizeAllFreeRegions,
+            query_state,
         )
     }
 
@@ -96,23 +93,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// out the [chapter in the rustc guide][c].
     ///
     /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#canonicalizing-the-query-result
-    pub fn canonicalize_response<V>(
-        &self,
-        value: &V,
-    ) -> Canonicalized<'gcx, V>
+    pub fn canonicalize_response<V>(&self, value: &V) -> Canonicalized<'gcx, V>
     where
         V: TypeFoldable<'tcx> + Lift<'gcx>,
     {
-        let mut var_values = SmallVec::new();
+        let mut query_state = OriginalQueryValues::default();
         Canonicalizer::canonicalize(
             value,
             Some(self),
             self.tcx,
-            CanonicalizeRegionMode {
-                static_region: false,
-                other_free_regions: false,
-            },
-            &mut var_values
+            &CanonicalizeQueryResponse,
+            &mut query_state,
         )
     }
 
@@ -128,7 +119,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     pub fn canonicalize_hr_query_hack<V>(
         &self,
         value: &V,
-        var_values: &mut SmallCanonicalVarValues<'tcx>
+        query_state: &mut OriginalQueryValues<'tcx>,
     ) -> Canonicalized<'gcx, V>
     where
         V: TypeFoldable<'tcx> + Lift<'gcx>,
@@ -143,27 +134,87 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
             value,
             Some(self),
             self.tcx,
-            CanonicalizeRegionMode {
-                static_region: false,
-                other_free_regions: true,
-            },
-            var_values
+            &CanonicalizeFreeRegionsOtherThanStatic,
+            query_state,
         )
     }
 }
 
-/// If this flag is true, then all free regions will be replaced with
-/// a canonical var. This is used to make queries as generic as
-/// possible. For example, the query `F: Foo<'static>` would be
-/// canonicalized to `F: Foo<'0>`.
-struct CanonicalizeRegionMode {
-    static_region: bool,
-    other_free_regions: bool,
+/// Controls how we canonicalize "free regions" that are not inference
+/// variables. This depends on what we are canonicalizing *for* --
+/// e.g., if we are canonicalizing to create a query, we want to
+/// replace those with inference variables, since we want to make a
+/// maximally general query. But if we are canonicalizing a *query
+/// response*, then we don't typically replace free regions, as they
+/// must have been introduced from other parts of the system.
+trait CanonicalizeRegionMode {
+    fn canonicalize_free_region(
+        &self,
+        canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
+        r: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx>;
+
+    fn any(&self) -> bool;
+}
+
+struct CanonicalizeQueryResponse;
+
+impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
+    fn canonicalize_free_region(
+        &self,
+        _canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
+        r: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx> {
+        match r {
+            ty::ReFree(_) | ty::ReEmpty | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r,
+            _ => {
+                // Other than `'static` or `'empty`, the query
+                // response should be executing in a fully
+                // canonicalized environment, so there shouldn't be
+                // any other region names it can come up.
+                bug!("unexpected region in query response: `{:?}`", r)
+            }
+        }
+    }
+
+    fn any(&self) -> bool {
+        false
+    }
 }
 
-impl CanonicalizeRegionMode {
+struct CanonicalizeAllFreeRegions;
+
+impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
+    fn canonicalize_free_region(
+        &self,
+        canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
+        r: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx> {
+        canonicalizer.canonical_var_for_region(r)
+    }
+
     fn any(&self) -> bool {
-        self.static_region || self.other_free_regions
+        true
+    }
+}
+
+struct CanonicalizeFreeRegionsOtherThanStatic;
+
+impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
+    fn canonicalize_free_region(
+        &self,
+        canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
+        r: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx> {
+        if let ty::ReStatic = r {
+            r
+        } else {
+            canonicalizer.canonical_var_for_region(r)
+        }
+    }
+
+    fn any(&self) -> bool {
+        true
     }
 }
 
@@ -171,11 +222,11 @@ struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>,
     tcx: TyCtxt<'cx, 'gcx, 'tcx>,
     variables: SmallVec<[CanonicalVarInfo; 8]>,
-    var_values: &'cx mut SmallCanonicalVarValues<'tcx>,
+    query_state: &'cx mut OriginalQueryValues<'tcx>,
     // Note that indices is only used once `var_values` is big enough to be
     // heap-allocated.
     indices: FxHashMap<Kind<'tcx>, CanonicalVar>,
-    canonicalize_region_mode: CanonicalizeRegionMode,
+    canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode,
     needs_canonical_flags: TypeFlags,
 }
 
@@ -192,51 +243,25 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
             }
 
             ty::ReVar(vid) => {
-                let r = self
-                    .infcx
+                let r = self.infcx
                     .unwrap()
                     .borrow_region_constraints()
                     .opportunistic_resolve_var(self.tcx, vid);
-                let info = CanonicalVarInfo {
-                    kind: CanonicalVarKind::Region,
-                };
                 debug!(
                     "canonical: region var found with vid {:?}, \
                      opportunistically resolved to {:?}",
                     vid, r
                 );
-                let cvar = self.canonical_var(info, r.into());
-                self.tcx().mk_region(ty::ReCanonical(cvar))
-            }
-
-            ty::ReStatic => {
-                if self.canonicalize_region_mode.static_region {
-                    let info = CanonicalVarInfo {
-                        kind: CanonicalVarKind::Region,
-                    };
-                    let cvar = self.canonical_var(info, r.into());
-                    self.tcx().mk_region(ty::ReCanonical(cvar))
-                } else {
-                    r
-                }
+                self.canonical_var_for_region(r)
             }
 
-            ty::ReEarlyBound(..)
+            ty::ReStatic
+            | ty::ReEarlyBound(..)
             | ty::ReFree(_)
             | ty::ReScope(_)
             | ty::RePlaceholder(..)
             | ty::ReEmpty
-            | ty::ReErased => {
-                if self.canonicalize_region_mode.other_free_regions {
-                    let info = CanonicalVarInfo {
-                        kind: CanonicalVarKind::Region,
-                    };
-                    let cvar = self.canonical_var(info, r.into());
-                    self.tcx().mk_region(ty::ReCanonical(cvar))
-                } else {
-                    r
-                }
-            }
+            | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
 
             ty::ReClosureBound(..) | ty::ReCanonical(_) => {
                 bug!("canonical region encountered during canonicalization")
@@ -302,10 +327,10 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
     /// `canonicalize_query` and `canonicalize_response`.
     fn canonicalize<V>(
         value: &V,
-        infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>,
-        tcx: TyCtxt<'cx, 'gcx, 'tcx>,
-        canonicalize_region_mode: CanonicalizeRegionMode,
-        var_values: &'cx mut SmallCanonicalVarValues<'tcx>
+        infcx: Option<&InferCtxt<'_, 'gcx, 'tcx>>,
+        tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        canonicalize_region_mode: &dyn CanonicalizeRegionMode,
+        query_state: &mut OriginalQueryValues<'tcx>,
     ) -> Canonicalized<'gcx, V>
     where
         V: TypeFoldable<'tcx> + Lift<'gcx>,
@@ -340,7 +365,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
             canonicalize_region_mode,
             needs_canonical_flags,
             variables: SmallVec::new(),
-            var_values,
+            query_state,
             indices: FxHashMap::default(),
         };
         let out_value = value.fold_with(&mut canonicalizer);
@@ -371,11 +396,13 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
     fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> CanonicalVar {
         let Canonicalizer {
             variables,
-            var_values,
+            query_state,
             indices,
             ..
         } = self;
 
+        let var_values = &mut query_state.var_values;
+
         // This code is hot. `variables` and `var_values` are usually small
         // (fewer than 8 elements ~95% of the time). They are SmallVec's to
         // avoid allocations in those cases. We also don't use `indices` to
@@ -398,28 +425,34 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
                 // fill up `indices` to facilitate subsequent lookups.
                 if var_values.spilled() {
                     assert!(indices.is_empty());
-                    *indices =
-                        var_values.iter()
-                            .enumerate()
-                            .map(|(i, &kind)| (kind, CanonicalVar::new(i)))
-                            .collect();
+                    *indices = var_values
+                        .iter()
+                        .enumerate()
+                        .map(|(i, &kind)| (kind, CanonicalVar::new(i)))
+                        .collect();
                 }
                 // The cv is the index of the appended element.
                 CanonicalVar::new(var_values.len() - 1)
             }
         } else {
             // `var_values` is large. Do a hashmap search via `indices`.
-            *indices
-                .entry(kind)
-                .or_insert_with(|| {
-                    variables.push(info);
-                    var_values.push(kind);
-                    assert_eq!(variables.len(), var_values.len());
-                    CanonicalVar::new(variables.len() - 1)
-                })
+            *indices.entry(kind).or_insert_with(|| {
+                variables.push(info);
+                var_values.push(kind);
+                assert_eq!(variables.len(), var_values.len());
+                CanonicalVar::new(variables.len() - 1)
+            })
         }
     }
 
+    fn canonical_var_for_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        let info = CanonicalVarInfo {
+            kind: CanonicalVarKind::Region,
+        };
+        let cvar = self.canonical_var(info, r.into());
+        self.tcx().mk_region(ty::ReCanonical(cvar))
+    }
+
     /// Given a type variable `ty_var` of the given kind, first check
     /// if `ty_var` is bound to anything; if so, canonicalize
     /// *that*. Otherwise, create a new canonical variable for
diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs
index 85aa4f62f214c..a78b5b7d07264 100644
--- a/src/librustc/infer/canonical/mod.rs
+++ b/src/librustc/infer/canonical/mod.rs
@@ -44,7 +44,7 @@ use ty::{self, CanonicalVar, Lift, Region, List, TyCtxt};
 
 mod canonicalizer;
 
-pub mod query_result;
+pub mod query_response;
 
 mod substitute;
 
@@ -75,9 +75,16 @@ pub struct CanonicalVarValues<'tcx> {
     pub var_values: IndexVec<CanonicalVar, Kind<'tcx>>,
 }
 
-/// Like CanonicalVarValues, but for use in places where a SmallVec is
-/// appropriate.
-pub type SmallCanonicalVarValues<'tcx> = SmallVec<[Kind<'tcx>; 8]>;
+/// When we canonicalize a value to form a query, we wind up replacing
+/// various parts of it with canonical variables. This struct stores
+/// those replaced bits to remember for when we process the query
+/// result.
+#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
+pub struct OriginalQueryValues<'tcx> {
+    /// This is equivalent to `CanonicalVarValues`, but using a
+    /// `SmallVec` yields a significant performance win.
+    pub var_values: SmallVec<[Kind<'tcx>; 8]>,
+}
 
 /// Information about a canonical variable that is included with the
 /// canonical value. This is sufficient information for code to create
@@ -118,10 +125,10 @@ pub enum CanonicalTyVarKind {
 }
 
 /// After we execute a query with a canonicalized key, we get back a
-/// `Canonical<QueryResult<..>>`. You can use
+/// `Canonical<QueryResponse<..>>`. You can use
 /// `instantiate_query_result` to access the data in this result.
 #[derive(Clone, Debug)]
-pub struct QueryResult<'tcx, R> {
+pub struct QueryResponse<'tcx, R> {
     pub var_values: CanonicalVarValues<'tcx>,
     pub region_constraints: Vec<QueryRegionConstraint<'tcx>>,
     pub certainty: Certainty,
@@ -130,8 +137,8 @@ pub struct QueryResult<'tcx, R> {
 
 pub type Canonicalized<'gcx, V> = Canonical<'gcx, <V as Lift<'gcx>>::Lifted>;
 
-pub type CanonicalizedQueryResult<'gcx, T> =
-    Lrc<Canonical<'gcx, QueryResult<'gcx, <T as Lift<'gcx>>::Lifted>>>;
+pub type CanonicalizedQueryResponse<'gcx, T> =
+    Lrc<Canonical<'gcx, QueryResponse<'gcx, <T as Lift<'gcx>>::Lifted>>>;
 
 /// Indicates whether or not we were able to prove the query to be
 /// true.
@@ -168,7 +175,7 @@ impl Certainty {
     }
 }
 
-impl<'tcx, R> QueryResult<'tcx, R> {
+impl<'tcx, R> QueryResponse<'tcx, R> {
     pub fn is_proven(&self) -> bool {
         self.certainty.is_proven()
     }
@@ -178,7 +185,7 @@ impl<'tcx, R> QueryResult<'tcx, R> {
     }
 }
 
-impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> {
+impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
     pub fn is_proven(&self) -> bool {
         self.value.is_proven()
     }
@@ -225,12 +232,16 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// inference variables and applies it to the canonical value.
     /// Returns both the instantiated result *and* the substitution S.
     ///
-    /// This is useful at the start of a query: it basically brings
-    /// the canonical value "into scope" within your new infcx. At the
-    /// end of processing, the substitution S (once canonicalized)
-    /// then represents the values that you computed for each of the
-    /// canonical inputs to your query.
-    pub fn instantiate_canonical_with_fresh_inference_vars<T>(
+    /// This is only meant to be invoked as part of constructing an
+    /// inference context at the start of a query (see
+    /// `InferCtxtBuilder::enter_with_canonical`).  It basically
+    /// brings the canonical value "into scope" within your new infcx.
+    ///
+    /// At the end of processing, the substitution S (once
+    /// canonicalized) then represents the values that you computed
+    /// for each of the canonical inputs to your query.
+
+    pub(in infer) fn instantiate_canonical_with_fresh_inference_vars<T>(
         &self,
         span: Span,
         canonical: &Canonical<'tcx, T>,
@@ -238,6 +249,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
+        assert_eq!(self.universe(), ty::UniverseIndex::ROOT, "infcx not newly created");
+        assert_eq!(self.type_variables.borrow().num_vars(), 0, "infcx not newly created");
+
         let canonical_inference_vars =
             self.fresh_inference_vars_for_canonical_vars(span, canonical.variables);
         let result = canonical.substitute(self.tcx, &canonical_inference_vars);
@@ -344,14 +358,14 @@ BraceStructTypeFoldableImpl! {
 }
 
 BraceStructTypeFoldableImpl! {
-    impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> {
+    impl<'tcx, R> TypeFoldable<'tcx> for QueryResponse<'tcx, R> {
         var_values, region_constraints, certainty, value
     } where R: TypeFoldable<'tcx>,
 }
 
 BraceStructLiftImpl! {
-    impl<'a, 'tcx, R> Lift<'tcx> for QueryResult<'a, R> {
-        type Lifted = QueryResult<'tcx, R::Lifted>;
+    impl<'a, 'tcx, R> Lift<'tcx> for QueryResponse<'a, R> {
+        type Lifted = QueryResponse<'tcx, R::Lifted>;
         var_values, region_constraints, certainty, value
     } where R: Lift<'tcx>
 }
diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_response.rs
similarity index 82%
rename from src/librustc/infer/canonical/query_result.rs
rename to src/librustc/infer/canonical/query_response.rs
index a327f1f5c9d50..c29a75c34cf9d 100644
--- a/src/librustc/infer/canonical/query_result.rs
+++ b/src/librustc/infer/canonical/query_response.rs
@@ -19,8 +19,8 @@
 
 use infer::canonical::substitute::substitute_value;
 use infer::canonical::{
-    Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResult, Certainty,
-    QueryRegionConstraint, QueryResult, SmallCanonicalVarValues,
+    Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResponse, Certainty,
+    OriginalQueryValues, QueryRegionConstraint, QueryResponse,
 };
 use infer::region_constraints::{Constraint, RegionConstraintData};
 use infer::InferCtxtBuilder;
@@ -59,18 +59,20 @@ impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
         canonical_key: &Canonical<'tcx, K>,
         operation: impl FnOnce(&InferCtxt<'_, 'gcx, 'tcx>, &mut FulfillmentContext<'tcx>, K)
             -> Fallible<R>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, R>>
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, R>>
     where
         K: TypeFoldable<'tcx>,
         R: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
     {
-        self.enter(|ref infcx| {
-            let (key, canonical_inference_vars) =
-                infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_key);
-            let fulfill_cx = &mut FulfillmentContext::new();
-            let value = operation(infcx, fulfill_cx, key)?;
-            infcx.make_canonicalized_query_result(canonical_inference_vars, value, fulfill_cx)
-        })
+        self.enter_with_canonical(
+            DUMMY_SP,
+            canonical_key,
+            |ref infcx, key, canonical_inference_vars| {
+                let fulfill_cx = &mut FulfillmentContext::new();
+                let value = operation(infcx, fulfill_cx, key)?;
+                infcx.make_canonicalized_query_response(canonical_inference_vars, value, fulfill_cx)
+            },
+        )
     }
 }
 
@@ -94,41 +96,41 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     ///   the same thing happens, but the resulting query is marked as ambiguous.
     /// - Finally, if any of the obligations result in a hard error,
     ///   then `Err(NoSolution)` is returned.
-    pub fn make_canonicalized_query_result<T>(
+    pub fn make_canonicalized_query_response<T>(
         &self,
         inference_vars: CanonicalVarValues<'tcx>,
         answer: T,
         fulfill_cx: &mut FulfillmentContext<'tcx>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, T>>
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, T>>
     where
         T: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
     {
-        let query_result = self.make_query_result(inference_vars, answer, fulfill_cx)?;
-        let canonical_result = self.canonicalize_response(&query_result);
+        let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?;
+        let canonical_result = self.canonicalize_response(&query_response);
 
         debug!(
-            "make_canonicalized_query_result: canonical_result = {:#?}",
+            "make_canonicalized_query_response: canonical_result = {:#?}",
             canonical_result
         );
 
         Ok(Lrc::new(canonical_result))
     }
 
-    /// Helper for `make_canonicalized_query_result` that does
+    /// Helper for `make_canonicalized_query_response` that does
     /// everything up until the final canonicalization.
-    fn make_query_result<T>(
+    fn make_query_response<T>(
         &self,
         inference_vars: CanonicalVarValues<'tcx>,
         answer: T,
         fulfill_cx: &mut FulfillmentContext<'tcx>,
-    ) -> Result<QueryResult<'tcx, T>, NoSolution>
+    ) -> Result<QueryResponse<'tcx, T>, NoSolution>
     where
         T: Debug + TypeFoldable<'tcx> + Lift<'gcx>,
     {
         let tcx = self.tcx;
 
         debug!(
-            "make_query_result(\
+            "make_query_response(\
              inference_vars={:?}, \
              answer={:?})",
             inference_vars, answer,
@@ -140,7 +142,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
 
         if !true_errors.is_empty() {
             // FIXME -- we don't indicate *why* we failed to solve
-            debug!("make_query_result: true_errors={:#?}", true_errors);
+            debug!("make_query_response: true_errors={:#?}", true_errors);
             return Err(NoSolution);
         }
 
@@ -155,7 +157,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
                 region_obligations
                     .iter()
                     .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)),
-                region_constraints)
+                region_constraints,
+            )
         });
 
         let certainty = if ambig_errors.is_empty() {
@@ -164,7 +167,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
             Certainty::Ambiguous
         };
 
-        Ok(QueryResult {
+        Ok(QueryResponse {
             var_values: inference_vars,
             region_constraints,
             certainty,
@@ -182,12 +185,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// out the [chapter in the rustc guide][c].
     ///
     /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#processing-the-canonicalized-query-result
-    pub fn instantiate_query_result_and_region_obligations<R>(
+    pub fn instantiate_query_response_and_region_obligations<R>(
         &self,
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        original_values: &SmallCanonicalVarValues<'tcx>,
-        query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
+        original_values: &OriginalQueryValues<'tcx>,
+        query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
     ) -> InferResult<'tcx, R>
     where
         R: Debug + TypeFoldable<'tcx>,
@@ -195,17 +198,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         let InferOk {
             value: result_subst,
             mut obligations,
-        } = self.query_result_substitution(cause, param_env, original_values, query_result)?;
+        } = self.query_response_substitution(cause, param_env, original_values, query_response)?;
 
         obligations.extend(self.query_region_constraints_into_obligations(
             cause,
             param_env,
-            &query_result.value.region_constraints,
+            &query_response.value.region_constraints,
             &result_subst,
         ));
 
         let user_result: R =
-            query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
+            query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
 
         Ok(InferOk {
             value: user_result,
@@ -214,7 +217,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     }
 
     /// An alternative to
-    /// `instantiate_query_result_and_region_obligations` that is more
+    /// `instantiate_query_response_and_region_obligations` that is more
     /// efficient for NLL. NLL is a bit more advanced in the
     /// "transition to chalk" than the rest of the compiler. During
     /// the NLL type check, all of the "processing" of types and
@@ -229,8 +232,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// into the older infcx-style constraints (e.g., calls to
     /// `sub_regions` or `register_region_obligation`).
     ///
-    /// Therefore, `instantiate_nll_query_result_and_region_obligations` performs the same
-    /// basic operations as `instantiate_query_result_and_region_obligations` but
+    /// Therefore, `instantiate_nll_query_response_and_region_obligations` performs the same
+    /// basic operations as `instantiate_query_response_and_region_obligations` but
     /// it returns its result differently:
     ///
     /// - It creates a substitution `S` that maps from the original
@@ -248,12 +251,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     ///   are propagated back in the return value.
     /// - Finally, the query result (of type `R`) is propagated back,
     ///   after applying the substitution `S`.
-    pub fn instantiate_nll_query_result_and_region_obligations<R>(
+    pub fn instantiate_nll_query_response_and_region_obligations<R>(
         &self,
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        original_values: &SmallCanonicalVarValues<'tcx>,
-        query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
+        original_values: &OriginalQueryValues<'tcx>,
+        query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
         output_query_region_constraints: &mut Vec<QueryRegionConstraint<'tcx>>,
     ) -> InferResult<'tcx, R>
     where
@@ -261,22 +264,22 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     {
         // In an NLL query, there should be no type variables in the
         // query, only region variables.
-        debug_assert!(query_result.variables.iter().all(|v| match v.kind {
+        debug_assert!(query_response.variables.iter().all(|v| match v.kind {
             CanonicalVarKind::Ty(_) => false,
             CanonicalVarKind::Region => true,
         }));
 
         let result_subst =
-            self.query_result_substitution_guess(cause, original_values, query_result);
+            self.query_response_substitution_guess(cause, original_values, query_response);
 
         // Compute `QueryRegionConstraint` values that unify each of
         // the original values `v_o` that was canonicalized into a
         // variable...
         let mut obligations = vec![];
 
-        for (index, original_value) in original_values.iter().enumerate() {
+        for (index, original_value) in original_values.var_values.iter().enumerate() {
             // ...with the value `v_r` of that variable from the query.
-            let result_value = query_result.substitute_projected(self.tcx, &result_subst, |v| {
+            let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
                 &v.var_values[CanonicalVar::new(index)]
             });
             match (original_value.unpack(), result_value.unpack()) {
@@ -311,7 +314,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
 
         // ...also include the other query region constraints from the query.
         output_query_region_constraints.extend(
-            query_result.value.region_constraints.iter().filter_map(|r_c| {
+            query_response.value.region_constraints.iter().filter_map(|r_c| {
                 let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below
                 let k1 = substitute_value(self.tcx, &result_subst, &k1);
                 let r2 = substitute_value(self.tcx, &result_subst, &r2);
@@ -324,7 +327,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         );
 
         let user_result: R =
-            query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
+            query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
 
         Ok(InferOk {
             value: user_result,
@@ -342,30 +345,30 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// example) we are doing lazy normalization and the value
     /// assigned to a type variable is unified with an unnormalized
     /// projection.
-    fn query_result_substitution<R>(
+    fn query_response_substitution<R>(
         &self,
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        original_values: &SmallCanonicalVarValues<'tcx>,
-        query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
+        original_values: &OriginalQueryValues<'tcx>,
+        query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
     ) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
     where
         R: Debug + TypeFoldable<'tcx>,
     {
         debug!(
-            "query_result_substitution(original_values={:#?}, query_result={:#?})",
-            original_values, query_result,
+            "query_response_substitution(original_values={:#?}, query_response={:#?})",
+            original_values, query_response,
         );
 
         let result_subst =
-            self.query_result_substitution_guess(cause, original_values, query_result);
+            self.query_response_substitution_guess(cause, original_values, query_response);
 
-        let obligations = self.unify_query_result_substitution_guess(
+        let obligations = self.unify_query_response_substitution_guess(
             cause,
             param_env,
             original_values,
             &result_subst,
-            query_result,
+            query_response,
         )?
             .into_obligations();
 
@@ -384,26 +387,26 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// will instantiate fresh inference variables for each canonical
     /// variable instead. Therefore, the result of this method must be
     /// properly unified
-    fn query_result_substitution_guess<R>(
+    fn query_response_substitution_guess<R>(
         &self,
         cause: &ObligationCause<'tcx>,
-        original_values: &SmallCanonicalVarValues<'tcx>,
-        query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
+        original_values: &OriginalQueryValues<'tcx>,
+        query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
     ) -> CanonicalVarValues<'tcx>
     where
         R: Debug + TypeFoldable<'tcx>,
     {
         debug!(
-            "query_result_substitution_guess(original_values={:#?}, query_result={:#?})",
-            original_values, query_result,
+            "query_response_substitution_guess(original_values={:#?}, query_response={:#?})",
+            original_values, query_response,
         );
 
         // Every canonical query result includes values for each of
         // the inputs to the query. Therefore, we begin by unifying
         // these values with the original inputs that were
         // canonicalized.
-        let result_values = &query_result.value.var_values;
-        assert_eq!(original_values.len(), result_values.len());
+        let result_values = &query_response.value.var_values;
+        assert_eq!(original_values.var_values.len(), result_values.len());
 
         // Quickly try to find initial values for the canonical
         // variables in the result in terms of the query. We do this
@@ -413,11 +416,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         // result, then we can type the corresponding value from the
         // input. See the example above.
         let mut opt_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>> =
-            IndexVec::from_elem_n(None, query_result.variables.len());
+            IndexVec::from_elem_n(None, query_response.variables.len());
 
         // In terms of our example above, we are iterating over pairs like:
         // [(?A, Vec<?0>), ('static, '?1), (?B, ?0)]
-        for (original_value, result_value) in original_values.iter().zip(result_values) {
+        for (original_value, result_value) in original_values.var_values.iter().zip(result_values) {
             match result_value.unpack() {
                 UnpackedKind::Type(result_value) => {
                     // e.g., here `result_value` might be `?0` in the example above...
@@ -440,7 +443,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         // given variable in the loop above, use that. Otherwise, use
         // a fresh inference variable.
         let result_subst = CanonicalVarValues {
-            var_values: query_result
+            var_values: query_response
                 .variables
                 .iter()
                 .enumerate()
@@ -458,29 +461,34 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// query result.  Often, but not always, this is a no-op, because
     /// we already found the mapping in the "guessing" step.
     ///
-    /// See also: `query_result_substitution_guess`
-    fn unify_query_result_substitution_guess<R>(
+    /// See also: `query_response_substitution_guess`
+    fn unify_query_response_substitution_guess<R>(
         &self,
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        original_values: &SmallCanonicalVarValues<'tcx>,
+        original_values: &OriginalQueryValues<'tcx>,
         result_subst: &CanonicalVarValues<'tcx>,
-        query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
+        query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
     ) -> InferResult<'tcx, ()>
     where
         R: Debug + TypeFoldable<'tcx>,
     {
         // A closure that yields the result value for the given
         // canonical variable; this is taken from
-        // `query_result.var_values` after applying the substitution
+        // `query_response.var_values` after applying the substitution
         // `result_subst`.
-        let substituted_query_result = |index: CanonicalVar| -> Kind<'tcx> {
-            query_result.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index])
+        let substituted_query_response = |index: CanonicalVar| -> Kind<'tcx> {
+            query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index])
         };
 
         // Unify the original value for each variable with the value
-        // taken from `query_result` (after applying `result_subst`).
-        Ok(self.unify_canonical_vars(cause, param_env, original_values, substituted_query_result)?)
+        // taken from `query_response` (after applying `result_subst`).
+        Ok(self.unify_canonical_vars(
+            cause,
+            param_env,
+            original_values,
+            substituted_query_response,
+        )?)
     }
 
     /// Converts the region constraints resulting from a query into an
@@ -524,12 +532,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         &self,
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        variables1: &SmallCanonicalVarValues<'tcx>,
+        variables1: &OriginalQueryValues<'tcx>,
         variables2: impl Fn(CanonicalVar) -> Kind<'tcx>,
     ) -> InferResult<'tcx, ()> {
         self.commit_if_ok(|_| {
             let mut obligations = vec![];
-            for (index, value1) in variables1.iter().enumerate() {
+            for (index, value1) in variables1.var_values.iter().enumerate() {
                 let value2 = variables2(CanonicalVar::new(index));
 
                 match (value1.unpack(), value2.unpack()) {
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index e77d20665bf3b..ae1892caa744e 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -593,11 +593,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     where
         T : TypeFoldable<'tcx>,
     {
-        let new_universe = self.create_subuniverse();
+        let next_universe = self.create_next_universe();
 
         let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
             self.tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
-                universe: new_universe,
+                universe: next_universe,
                 name: br,
             }))
         });
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 291b46edccfb2..ef9886e06d4be 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -20,6 +20,7 @@ pub use ty::IntVarValue;
 use arena::SyncDroplessArena;
 use errors::DiagnosticBuilder;
 use hir::def_id::DefId;
+use infer::canonical::{Canonical, CanonicalVarValues};
 use middle::free_region::RegionRelations;
 use middle::lang_items;
 use middle::region;
@@ -49,7 +50,6 @@ use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
 use self::type_variable::TypeVariableOrigin;
 use self::unify_key::ToType;
 
-pub mod opaque_types;
 pub mod at;
 pub mod canonical;
 mod combine;
@@ -62,6 +62,7 @@ mod higher_ranked;
 pub mod lattice;
 mod lexical_region_resolve;
 mod lub;
+pub mod opaque_types;
 pub mod outlives;
 pub mod region_constraints;
 pub mod resolve;
@@ -86,7 +87,7 @@ pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
 /// NLL borrow checker will also do -- it might be set to true.
 #[derive(Copy, Clone, Default, Debug)]
 pub struct SuppressRegionErrors {
-    suppressed: bool
+    suppressed: bool,
 }
 
 impl SuppressRegionErrors {
@@ -100,15 +101,11 @@ impl SuppressRegionErrors {
     pub fn when_nll_is_enabled(tcx: TyCtxt<'_, '_, '_>) -> Self {
         match tcx.borrowck_mode() {
             // If we're on AST or Migrate mode, report AST region errors
-            BorrowckMode::Ast | BorrowckMode::Migrate => SuppressRegionErrors {
-                suppressed: false
-            },
+            BorrowckMode::Ast | BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false },
 
             // If we're on MIR or Compare mode, don't report AST region errors as they should
             // be reported by NLL
-            BorrowckMode::Compare | BorrowckMode::Mir => SuppressRegionErrors {
-                suppressed: true
-            },
+            BorrowckMode::Compare | BorrowckMode::Mir => SuppressRegionErrors { suppressed: true },
         }
     }
 }
@@ -494,10 +491,30 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
         self
     }
 
-    pub fn enter<F, R>(&'tcx mut self, f: F) -> R
+    /// Given a canonical value `C` as a starting point, create an
+    /// inference context that contains each of the bound values
+    /// within instantiated as a fresh variable. The `f` closure is
+    /// invoked with the new infcx, along with the instantiated value
+    /// `V` and a substitution `S`.  This substitution `S` maps from
+    /// the bound values in `C` to their instantiated values in `V`
+    /// (in other words, `S(C) = V`).
+    pub fn enter_with_canonical<T, R>(
+        &'tcx mut self,
+        span: Span,
+        canonical: &Canonical<'tcx, T>,
+        f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>, T, CanonicalVarValues<'tcx>) -> R,
+    ) -> R
     where
-        F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R,
+        T: TypeFoldable<'tcx>,
     {
+        self.enter(|infcx| {
+            let (value, subst) =
+                infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
+            f(infcx, value, subst)
+        })
+    }
+
+    pub fn enter<R>(&'tcx mut self, f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R) -> R {
         let InferCtxtBuilder {
             global_tcx,
             ref arena,
@@ -1472,13 +1489,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.universe.get()
     }
 
-    /// Create and return a new subunivese of the current universe;
-    /// update `self.universe` to that new subuniverse. At present,
-    /// used only in the NLL subtyping code, which uses the new
-    /// universe-based scheme instead of the more limited leak-check
-    /// scheme.
-    pub fn create_subuniverse(&self) -> ty::UniverseIndex {
-        let u = self.universe.get().subuniverse();
+    /// Create and return a fresh universe that extends all previous
+    /// universes. Updates `self.universe` to that new universe.
+    pub fn create_next_universe(&self) -> ty::UniverseIndex {
+        let u = self.universe.get().next_universe();
         self.universe.set(u);
         u
     }
diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs
index aaf03f8e7fb55..8f7b0df8b95aa 100644
--- a/src/librustc/traits/query/dropck_outlives.rs
+++ b/src/librustc/traits/query/dropck_outlives.rs
@@ -10,7 +10,7 @@
 
 use infer::at::At;
 use infer::InferOk;
-use smallvec::SmallVec;
+use infer::canonical::OriginalQueryValues;
 use std::iter::FromIterator;
 use syntax::source_map::Span;
 use ty::subst::Kind;
@@ -51,14 +51,14 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> {
         }
 
         let gcx = tcx.global_tcx();
-        let mut orig_values = SmallVec::new();
+        let mut orig_values = OriginalQueryValues::default();
         let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values);
         let span = self.cause.span;
         debug!("c_ty = {:?}", c_ty);
         match &gcx.dropck_outlives(c_ty) {
             Ok(result) if result.is_proven() => {
                 if let Ok(InferOk { value, obligations }) =
-                    self.infcx.instantiate_query_result_and_region_obligations(
+                    self.infcx.instantiate_query_response_and_region_obligations(
                     self.cause,
                     self.param_env,
                     &orig_values,
diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs
index f573b1ef45e9c..ca11c5f5a0874 100644
--- a/src/librustc/traits/query/evaluate_obligation.rs
+++ b/src/librustc/traits/query/evaluate_obligation.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use infer::InferCtxt;
-use smallvec::SmallVec;
+use infer::canonical::OriginalQueryValues;
 use traits::{EvaluationResult, PredicateObligation, SelectionContext,
              TraitQueryMode, OverflowError};
 
@@ -38,7 +38,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        let mut _orig_values = SmallVec::new();
+        let mut _orig_values = OriginalQueryValues::default();
         let c_pred = self.canonicalize_query(&obligation.param_env.and(obligation.predicate),
                                              &mut _orig_values);
         // Run canonical query. If overflow occurs, rerun from scratch but this time
diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs
index 9b9643aab97d5..4adb65dc58d91 100644
--- a/src/librustc/traits/query/normalize.rs
+++ b/src/librustc/traits/query/normalize.rs
@@ -13,9 +13,9 @@
 //! `normalize_projection_ty` query when it encounters projections.
 
 use infer::at::At;
+use infer::canonical::OriginalQueryValues;
 use infer::{InferCtxt, InferOk};
 use mir::interpret::{ConstValue, GlobalId};
-use smallvec::SmallVec;
 use traits::project::Normalized;
 use traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
 use ty::fold::{TypeFoldable, TypeFolder};
@@ -154,7 +154,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
 
                 let gcx = self.infcx.tcx.global_tcx();
 
-                let mut orig_values = SmallVec::new();
+                let mut orig_values = OriginalQueryValues::default();
                 let c_data = self.infcx.canonicalize_query(
                     &self.param_env.and(*data), &mut orig_values);
                 debug!("QueryNormalizer: c_data = {:#?}", c_data);
@@ -167,7 +167,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
                             return ty;
                         }
 
-                        match self.infcx.instantiate_query_result_and_region_obligations(
+                        match self.infcx.instantiate_query_response_and_region_obligations(
                             self.cause,
                             self.param_env,
                             &orig_values,
diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs
index 47c8ee357fbe8..99f557d44d9aa 100644
--- a/src/librustc/traits/query/outlives_bounds.rs
+++ b/src/librustc/traits/query/outlives_bounds.rs
@@ -9,9 +9,9 @@
 // except according to those terms.
 
 use infer::InferCtxt;
+use infer::canonical::OriginalQueryValues;
 use syntax::ast;
 use syntax::source_map::Span;
-use smallvec::SmallVec;
 use traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt};
 use traits::query::NoSolution;
 use ty::{self, Ty, TyCtxt};
@@ -105,7 +105,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     ) -> Vec<OutlivesBound<'tcx>> {
         debug!("implied_outlives_bounds(ty = {:?})", ty);
 
-        let mut orig_values = SmallVec::new();
+        let mut orig_values = OriginalQueryValues::default();
         let key = self.canonicalize_query(&param_env.and(ty), &mut orig_values);
         let result = match self.tcx.global_tcx().implied_outlives_bounds(key) {
             Ok(r) => r,
@@ -119,7 +119,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         };
         assert!(result.value.is_proven());
 
-        let result = self.instantiate_query_result_and_region_obligations(
+        let result = self.instantiate_query_response_and_region_obligations(
             &ObligationCause::misc(span, body_id), param_env, &orig_values, &result);
         debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result);
         let result = match result {
diff --git a/src/librustc/traits/query/type_op/custom.rs b/src/librustc/traits/query/type_op/custom.rs
index 6708112697bb5..54860dd0434a0 100644
--- a/src/librustc/traits/query/type_op/custom.rs
+++ b/src/librustc/traits/query/type_op/custom.rs
@@ -12,7 +12,7 @@ use infer::{InferCtxt, InferOk};
 use std::fmt;
 use traits::query::Fallible;
 
-use infer::canonical::query_result;
+use infer::canonical::query_response;
 use infer::canonical::QueryRegionConstraint;
 use std::rc::Rc;
 use syntax::source_map::DUMMY_SP;
@@ -102,7 +102,7 @@ fn scrape_region_constraints<'gcx, 'tcx, R>(
 
     let region_constraint_data = infcx.take_and_reset_region_constraints();
 
-    let outlives = query_result::make_query_outlives(
+    let outlives = query_response::make_query_outlives(
         infcx.tcx,
         region_obligations
             .iter()
diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs
index 52a087cbc8069..43dea442df65a 100644
--- a/src/librustc/traits/query/type_op/eq.rs
+++ b/src/librustc/traits/query/type_op/eq.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult};
+use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
 use traits::query::Fallible;
 use ty::{ParamEnvAnd, Ty, TyCtxt};
 
@@ -25,12 +25,12 @@ impl<'tcx> Eq<'tcx> {
 }
 
 impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Eq<'tcx> {
-    type QueryResult = ();
+    type QueryResponse = ();
 
     fn try_fast_path(
         _tcx: TyCtxt<'_, 'gcx, 'tcx>,
         key: &ParamEnvAnd<'tcx, Eq<'tcx>>,
-    ) -> Option<Self::QueryResult> {
+    ) -> Option<Self::QueryResponse> {
         if key.value.a == key.value.b {
             Some(())
         } else {
@@ -41,13 +41,13 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Eq<'tcx> {
     fn perform_query(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, ()>> {
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, ()>> {
         tcx.type_op_eq(canonicalized)
     }
 
     fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResult<'gcx, ()>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> {
+        v: &'a CanonicalizedQueryResponse<'gcx, ()>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> {
         v
     }
 }
diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
index 27534bc8c3cf7..b113a322d370a 100644
--- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
+++ b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult};
+use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
 use traits::query::outlives_bounds::OutlivesBound;
 use traits::query::Fallible;
 use ty::{ParamEnvAnd, Ty, TyCtxt};
@@ -25,19 +25,19 @@ impl<'tcx> ImpliedOutlivesBounds<'tcx> {
 }
 
 impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ImpliedOutlivesBounds<'tcx> {
-    type QueryResult = Vec<OutlivesBound<'tcx>>;
+    type QueryResponse = Vec<OutlivesBound<'tcx>>;
 
     fn try_fast_path(
         _tcx: TyCtxt<'_, 'gcx, 'tcx>,
         _key: &ParamEnvAnd<'tcx, Self>,
-    ) -> Option<Self::QueryResult> {
+    ) -> Option<Self::QueryResponse> {
         None
     }
 
     fn perform_query(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self::QueryResult>> {
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self::QueryResponse>> {
         // FIXME the query should take a `ImpliedOutlivesBounds`
         let Canonical {
             variables,
@@ -56,8 +56,8 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ImpliedOutlivesBounds<
     }
 
     fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>> {
+        v: &'a CanonicalizedQueryResponse<'gcx, Self::QueryResponse>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>> {
         v
     }
 }
diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs
index 8e4236d1754c2..b292df758eeb5 100644
--- a/src/librustc/traits/query/type_op/mod.rs
+++ b/src/librustc/traits/query/type_op/mod.rs
@@ -8,10 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryRegionConstraint,
-                       QueryResult};
+use infer::canonical::{
+    Canonical, Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues,
+    QueryRegionConstraint, QueryResponse,
+};
 use infer::{InferCtxt, InferOk};
-use smallvec::SmallVec;
 use std::fmt;
 use std::rc::Rc;
 use traits::query::Fallible;
@@ -55,7 +56,7 @@ pub trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
 pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>:
     fmt::Debug + Sized + TypeFoldable<'tcx> + Lift<'gcx>
 {
-    type QueryResult: TypeFoldable<'tcx> + Lift<'gcx>;
+    type QueryResponse: TypeFoldable<'tcx> + Lift<'gcx>;
 
     /// Give query the option for a simple fast path that never
     /// actually hits the tcx cache lookup etc. Return `Some(r)` with
@@ -63,7 +64,7 @@ pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>:
     fn try_fast_path(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         key: &ParamEnvAnd<'tcx, Self>,
-    ) -> Option<Self::QueryResult>;
+    ) -> Option<Self::QueryResponse>;
 
     /// Performs the actual query with the canonicalized key -- the
     /// real work happens here. This method is not given an `infcx`
@@ -74,29 +75,29 @@ pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>:
     fn perform_query(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self::QueryResult>>;
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self::QueryResponse>>;
 
     /// Casts a lifted query result (which is in the gcx lifetime)
     /// into the tcx lifetime. This is always just an identity cast,
     /// but the generic code doesn't realize it -- put another way, in
-    /// the generic code, we have a `Lifted<'gcx, Self::QueryResult>`
-    /// and we want to convert that to a `Self::QueryResult`. This is
+    /// the generic code, we have a `Lifted<'gcx, Self::QueryResponse>`
+    /// and we want to convert that to a `Self::QueryResponse`. This is
     /// not a priori valid, so we can't do it -- but in practice, it
     /// is always a no-op (e.g., the lifted form of a type,
     /// `Ty<'gcx>`, is a subtype of `Ty<'tcx>`). So we have to push
     /// the operation into the impls that know more specifically what
-    /// `QueryResult` is. This operation would (maybe) be nicer with
+    /// `QueryResponse` is. This operation would (maybe) be nicer with
     /// something like HKTs or GATs, since then we could make
-    /// `QueryResult` parametric and `'gcx` and `'tcx` etc.
+    /// `QueryResponse` parametric and `'gcx` and `'tcx` etc.
     fn shrink_to_tcx_lifetime(
-        lifted_query_result: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>>;
+        lifted_query_result: &'a CanonicalizedQueryResponse<'gcx, Self::QueryResponse>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>>;
 
     fn fully_perform_into(
         query_key: ParamEnvAnd<'tcx, Self>,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
         output_query_region_constraints: &mut Vec<QueryRegionConstraint<'tcx>>,
-    ) -> Fallible<Self::QueryResult> {
+    ) -> Fallible<Self::QueryResponse> {
         if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
             return Ok(result);
         }
@@ -105,7 +106,7 @@ pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>:
         // `canonicalize_hr_query_hack` here because of things
         // like the subtype query, which go awry around
         // `'static` otherwise.
-        let mut canonical_var_values = SmallVec::new();
+        let mut canonical_var_values = OriginalQueryValues::default();
         let canonical_self =
             infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values);
         let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;
@@ -114,7 +115,7 @@ pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>:
         let param_env = query_key.param_env;
 
         let InferOk { value, obligations } = infcx
-            .instantiate_nll_query_result_and_region_obligations(
+            .instantiate_nll_query_response_and_region_obligations(
                 &ObligationCause::dummy(),
                 param_env,
                 &canonical_var_values,
@@ -145,7 +146,7 @@ impl<'gcx: 'tcx, 'tcx, Q> TypeOp<'gcx, 'tcx> for ParamEnvAnd<'tcx, Q>
 where
     Q: QueryTypeOp<'gcx, 'tcx>,
 {
-    type Output = Q::QueryResult;
+    type Output = Q::QueryResponse;
 
     fn fully_perform(
         self,
diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs
index 0c393fa4ca80f..c45e8b2554b0f 100644
--- a/src/librustc/traits/query/type_op/normalize.rs
+++ b/src/librustc/traits/query/type_op/normalize.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult};
+use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
 use std::fmt;
 use traits::query::Fallible;
 use ty::fold::TypeFoldable;
@@ -32,7 +32,7 @@ impl<'gcx: 'tcx, 'tcx, T> super::QueryTypeOp<'gcx, 'tcx> for Normalize<T>
 where
     T: Normalizable<'gcx, 'tcx>,
 {
-    type QueryResult = T;
+    type QueryResponse = T;
 
     fn try_fast_path(_tcx: TyCtxt<'_, 'gcx, 'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> {
         if !key.value.value.has_projections() {
@@ -45,13 +45,13 @@ where
     fn perform_query(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self::QueryResult>> {
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self::QueryResponse>> {
         T::type_op_method(tcx, canonicalized)
     }
 
     fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResult<'gcx, T>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, T>> {
+        v: &'a CanonicalizedQueryResponse<'gcx, T>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, T>> {
         T::shrink_to_tcx_lifetime(v)
     }
 }
@@ -60,13 +60,13 @@ pub trait Normalizable<'gcx, 'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'gcx>
     fn type_op_method(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self>>;
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self>>;
 
     /// Convert from the `'gcx` (lifted) form of `Self` into the `tcx`
     /// form of `Self`.
     fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResult<'gcx, Self>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>>;
+        v: &'a CanonicalizedQueryResponse<'gcx, Self>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>>;
 }
 
 impl Normalizable<'gcx, 'tcx> for Ty<'tcx>
@@ -76,13 +76,13 @@ where
     fn type_op_method(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self>> {
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self>> {
         tcx.type_op_normalize_ty(canonicalized)
     }
 
     fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResult<'gcx, Self>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> {
+        v: &'a CanonicalizedQueryResponse<'gcx, Self>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> {
         v
     }
 }
@@ -94,13 +94,13 @@ where
     fn type_op_method(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self>> {
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self>> {
         tcx.type_op_normalize_predicate(canonicalized)
     }
 
     fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResult<'gcx, Self>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> {
+        v: &'a CanonicalizedQueryResponse<'gcx, Self>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> {
         v
     }
 }
@@ -112,13 +112,13 @@ where
     fn type_op_method(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self>> {
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self>> {
         tcx.type_op_normalize_poly_fn_sig(canonicalized)
     }
 
     fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResult<'gcx, Self>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> {
+        v: &'a CanonicalizedQueryResponse<'gcx, Self>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> {
         v
     }
 }
@@ -130,13 +130,13 @@ where
     fn type_op_method(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self>> {
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self>> {
         tcx.type_op_normalize_fn_sig(canonicalized)
     }
 
     fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResult<'gcx, Self>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> {
+        v: &'a CanonicalizedQueryResponse<'gcx, Self>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self>> {
         v
     }
 }
diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc/traits/query/type_op/outlives.rs
index e41ae7a72f9c2..a36c5accd2a68 100644
--- a/src/librustc/traits/query/type_op/outlives.rs
+++ b/src/librustc/traits/query/type_op/outlives.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult};
+use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
 use traits::query::dropck_outlives::trivial_dropck_outlives;
 use traits::query::dropck_outlives::DropckOutlivesResult;
 use traits::query::Fallible;
@@ -29,12 +29,12 @@ impl super::QueryTypeOp<'gcx, 'tcx> for DropckOutlives<'tcx>
 where
     'gcx: 'tcx,
 {
-    type QueryResult = DropckOutlivesResult<'tcx>;
+    type QueryResponse = DropckOutlivesResult<'tcx>;
 
     fn try_fast_path(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         key: &ParamEnvAnd<'tcx, Self>,
-    ) -> Option<Self::QueryResult> {
+    ) -> Option<Self::QueryResponse> {
         if trivial_dropck_outlives(tcx, key.value.dropped_ty) {
             Some(DropckOutlivesResult::default())
         } else {
@@ -45,7 +45,7 @@ where
     fn perform_query(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self::QueryResult>> {
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self::QueryResponse>> {
         // Subtle: note that we are not invoking
         // `infcx.at(...).dropck_outlives(...)` here, but rather the
         // underlying `dropck_outlives` query. This same underlying
@@ -76,8 +76,8 @@ where
     }
 
     fn shrink_to_tcx_lifetime(
-        lifted_query_result: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>> {
+        lifted_query_result: &'a CanonicalizedQueryResponse<'gcx, Self::QueryResponse>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>> {
         lifted_query_result
     }
 }
diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs
index e1b3b3c436dab..460ddb2a138b5 100644
--- a/src/librustc/traits/query/type_op/prove_predicate.rs
+++ b/src/librustc/traits/query/type_op/prove_predicate.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult};
+use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
 use traits::query::Fallible;
 use ty::{ParamEnvAnd, Predicate, TyCtxt};
 
@@ -24,12 +24,12 @@ impl<'tcx> ProvePredicate<'tcx> {
 }
 
 impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ProvePredicate<'tcx> {
-    type QueryResult = ();
+    type QueryResponse = ();
 
     fn try_fast_path(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         key: &ParamEnvAnd<'tcx, Self>,
-    ) -> Option<Self::QueryResult> {
+    ) -> Option<Self::QueryResponse> {
         // Proving Sized, very often on "obviously sized" types like
         // `&T`, accounts for about 60% percentage of the predicates
         // we have to prove. No need to canonicalize and all that for
@@ -50,13 +50,13 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ProvePredicate<'tcx> {
     fn perform_query(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, ()>> {
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, ()>> {
         tcx.type_op_prove_predicate(canonicalized)
     }
 
     fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResult<'gcx, ()>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> {
+        v: &'a CanonicalizedQueryResponse<'gcx, ()>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> {
         v
     }
 }
diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs
index dc41bb1d6ab69..2b2939c644aa3 100644
--- a/src/librustc/traits/query/type_op/subtype.rs
+++ b/src/librustc/traits/query/type_op/subtype.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult};
+use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
 use traits::query::Fallible;
 use ty::{ParamEnvAnd, Ty, TyCtxt};
 
@@ -28,7 +28,7 @@ impl<'tcx> Subtype<'tcx> {
 }
 
 impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Subtype<'tcx> {
-    type QueryResult = ();
+    type QueryResponse = ();
 
     fn try_fast_path(_tcx: TyCtxt<'_, 'gcx, 'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()> {
         if key.value.sub == key.value.sup {
@@ -41,13 +41,13 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Subtype<'tcx> {
     fn perform_query(
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResult<'gcx, ()>> {
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, ()>> {
         tcx.type_op_subtype(canonicalized)
     }
 
     fn shrink_to_tcx_lifetime(
-        v: &'a CanonicalizedQueryResult<'gcx, ()>,
-    ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> {
+        v: &'a CanonicalizedQueryResponse<'gcx, ()>,
+    ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> {
         v
     }
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 2e8734a6aa8eb..4135d499c5853 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -57,6 +57,7 @@ use syntax::symbol::{keywords, Symbol, LocalInternedString, InternedString};
 use syntax_pos::{DUMMY_SP, Span};
 
 use smallvec;
+use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
                                            HashStable};
 
@@ -1456,10 +1457,10 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
 /// "Universes" are used during type- and trait-checking in the
 /// presence of `for<..>` binders to control what sets of names are
 /// visible. Universes are arranged into a tree: the root universe
-/// contains names that are always visible. But when you enter into
-/// some subuniverse, then it may add names that are only visible
-/// within that subtree (but it can still name the names of its
-/// ancestor universes).
+/// contains names that are always visible. Each child then adds a new
+/// set of names that are visible, in addition to those of its parent.
+/// We say that the child universe "extends" the parent universe with
+/// new names.
 ///
 /// To make this more concrete, consider this program:
 ///
@@ -1471,11 +1472,11 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
 /// ```
 ///
 /// The struct name `Foo` is in the root universe U0. But the type
-/// parameter `T`, introduced on `bar`, is in a subuniverse U1 --
-/// i.e., within `bar`, we can name both `T` and `Foo`, but outside of
-/// `bar`, we cannot name `T`. Then, within the type of `y`, the
-/// region `'a` is in a subuniverse U2 of U1, because we can name it
-/// inside the fn type but not outside.
+/// parameter `T`, introduced on `bar`, is in an extended universe U1
+/// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside
+/// of `bar`, we cannot name `T`. Then, within the type of `y`, the
+/// region `'a` is in a universe U2 that extends U1, because we can
+/// name it inside the fn type but not outside.
 ///
 /// Universes are used to do type- and trait-checking around these
 /// "forall" binders (also called **universal quantification**). The
@@ -1488,65 +1489,39 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
 /// declared, but a type name in a non-zero universe is a placeholder
 /// type -- an idealized representative of "types in general" that we
 /// use for checking generic functions.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
-pub struct UniverseIndex(u32);
-
-impl UniverseIndex {
-    /// The root universe, where things that the user defined are
-    /// visible.
-    pub const ROOT: Self = UniverseIndex(0);
+newtype_index! {
+    pub struct UniverseIndex {
+        DEBUG_FORMAT = "U{}",
+    }
+}
 
-    /// The "max universe" -- this isn't really a valid universe, but
-    /// it's useful sometimes as a "starting value" when you are
-    /// taking the minimum of a (non-empty!) set of universes.
-    pub const MAX: Self = UniverseIndex(::std::u32::MAX);
+impl_stable_hash_for!(struct UniverseIndex { private });
 
-    /// Creates a universe index from the given integer.  Not to be
-    /// used lightly lest you pick a bad value. But sometimes we
-    /// convert universe indices into integers and back for various
-    /// reasons.
-    pub fn from_u32(index: u32) -> Self {
-        UniverseIndex(index)
-    }
+impl UniverseIndex {
+    pub const ROOT: UniverseIndex = UniverseIndex::from_u32_const(0);
 
-    /// A "subuniverse" corresponds to being inside a `forall` quantifier.
-    /// So, for example, suppose we have this type in universe `U`:
+    /// Returns the "next" universe index in order -- this new index
+    /// is considered to extend all previous universes. This
+    /// corresponds to entering a `forall` quantifier.  So, for
+    /// example, suppose we have this type in universe `U`:
     ///
     /// ```
     /// for<'a> fn(&'a u32)
     /// ```
     ///
     /// Once we "enter" into this `for<'a>` quantifier, we are in a
-    /// subuniverse of `U` -- in this new universe, we can name the
-    /// region `'a`, but that region was not nameable from `U` because
-    /// it was not in scope there.
-    pub fn subuniverse(self) -> UniverseIndex {
-        UniverseIndex(self.0.checked_add(1).unwrap())
-    }
-
-    /// True if the names in this universe are a subset of the names in `other`.
-    pub fn is_subset_of(self, other: UniverseIndex) -> bool {
-        self.0 <= other.0
-    }
-
-    pub fn as_u32(&self) -> u32 {
-        self.0
-    }
-
-    pub fn as_usize(&self) -> usize {
-        self.0 as usize
-    }
-}
-
-impl fmt::Debug for UniverseIndex {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "U{}", self.as_u32())
-    }
-}
-
-impl From<u32> for UniverseIndex {
-    fn from(index: u32) -> Self {
-        UniverseIndex(index)
+    /// new universe that extends `U` -- in this new universe, we can
+    /// name the region `'a`, but that region was not nameable from
+    /// `U` because it was not in scope there.
+    pub fn next_universe(self) -> UniverseIndex {
+        UniverseIndex::from_u32(self.private.checked_add(1).unwrap())
+    }
+
+    /// True if `self` can name a name from `other` -- in other words,
+    /// if the set of names in `self` is a superset of those in
+    /// `other`.
+    pub fn can_name(self, other: UniverseIndex) -> bool {
+        self.private >= other.private
     }
 }
 
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 7f5bc35f91f9b..c4f39ffcd2067 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -559,7 +559,7 @@ define_queries! { <'tcx>
         [] fn normalize_projection_ty: NormalizeProjectionTy(
             CanonicalProjectionGoal<'tcx>
         ) -> Result<
-            Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, NormalizationResult<'tcx>>>>,
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>>,
             NoSolution,
         >,
 
@@ -571,7 +571,7 @@ define_queries! { <'tcx>
         [] fn implied_outlives_bounds: ImpliedOutlivesBounds(
             CanonicalTyGoal<'tcx>
         ) -> Result<
-            Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, Vec<OutlivesBound<'tcx>>>>>,
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>>,
             NoSolution,
         >,
 
@@ -579,7 +579,7 @@ define_queries! { <'tcx>
         [] fn dropck_outlives: DropckOutlives(
             CanonicalTyGoal<'tcx>
         ) -> Result<
-            Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>,
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>>,
             NoSolution,
         >,
 
@@ -593,7 +593,7 @@ define_queries! { <'tcx>
         [] fn type_op_eq: TypeOpEq(
             CanonicalTypeOpEqGoal<'tcx>
         ) -> Result<
-            Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, ()>>>,
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>,
             NoSolution,
         >,
 
@@ -601,7 +601,7 @@ define_queries! { <'tcx>
         [] fn type_op_subtype: TypeOpSubtype(
             CanonicalTypeOpSubtypeGoal<'tcx>
         ) -> Result<
-            Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, ()>>>,
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>,
             NoSolution,
         >,
 
@@ -609,7 +609,7 @@ define_queries! { <'tcx>
         [] fn type_op_prove_predicate: TypeOpProvePredicate(
             CanonicalTypeOpProvePredicateGoal<'tcx>
         ) -> Result<
-            Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, ()>>>,
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>,
             NoSolution,
         >,
 
@@ -617,7 +617,7 @@ define_queries! { <'tcx>
         [] fn type_op_normalize_ty: TypeOpNormalizeTy(
             CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>
         ) -> Result<
-            Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, Ty<'tcx>>>>,
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>>,
             NoSolution,
         >,
 
@@ -625,7 +625,7 @@ define_queries! { <'tcx>
         [] fn type_op_normalize_predicate: TypeOpNormalizePredicate(
             CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>>
         ) -> Result<
-            Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, ty::Predicate<'tcx>>>>,
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>>,
             NoSolution,
         >,
 
@@ -633,7 +633,7 @@ define_queries! { <'tcx>
         [] fn type_op_normalize_poly_fn_sig: TypeOpNormalizePolyFnSig(
             CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>>
         ) -> Result<
-            Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, ty::PolyFnSig<'tcx>>>>,
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>>,
             NoSolution,
         >,
 
@@ -641,7 +641,7 @@ define_queries! { <'tcx>
         [] fn type_op_normalize_fn_sig: TypeOpNormalizeFnSig(
             CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>>
         ) -> Result<
-            Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, ty::FnSig<'tcx>>>>,
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>>,
             NoSolution,
         >,
 
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 3f62883c6a57b..273799bd4bd34 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! {
     ::ty::ClosureKind,
     ::ty::IntVarValue,
     ::ty::ParamTy,
+    ::ty::UniverseIndex,
     ::ty::Variance,
     ::syntax_pos::Span,
 }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 56bb6a87d44fa..dd8a7f19a63bd 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -112,7 +112,7 @@ struct RegionDefinition<'tcx> {
     /// Which universe is this region variable defined in? This is
     /// most often `ty::UniverseIndex::ROOT`, but when we encounter
     /// forall-quantifiers like `for<'a> { 'a = 'b }`, we would create
-    /// the variable for `'a` in a subuniverse.
+    /// the variable for `'a` in a fresh universe that extends ROOT.
     universe: ty::UniverseIndex,
 
     /// If this is 'static or an early-bound region, then this is
@@ -339,11 +339,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
                 NLLRegionVariableOrigin::Placeholder(placeholder) => {
                     // Each placeholder region is only visible from
-                    // its universe `ui` and its superuniverses. So we
+                    // its universe `ui` and its extensions. So we
                     // can't just add it into `scc` unless the
                     // universe of the scc can name this region.
                     let scc_universe = self.scc_universes[scc];
-                    if placeholder.universe.is_subset_of(scc_universe) {
+                    if scc_universe.can_name(placeholder.universe) {
                         self.scc_values.add_element(scc, placeholder);
                     } else {
                         self.add_incompatible_universe(scc);
@@ -541,7 +541,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // Quick check: if scc_b's declared universe is a subset of
         // scc_a's declared univese (typically, both are ROOT), then
         // it cannot contain any problematic universe elements.
-        if self.scc_universes[scc_b].is_subset_of(universe_a) {
+        if universe_a.can_name(self.scc_universes[scc_b]) {
             return true;
         }
 
@@ -550,7 +550,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // from universe_a
         self.scc_values
             .placeholders_contained_in(scc_b)
-            .all(|p| p.universe.is_subset_of(universe_a))
+            .all(|p| universe_a.can_name(p.universe))
     }
 
     /// Extend `scc` so that it can outlive some placeholder region
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
index 07372c19c46c9..3607ae4f5088d 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
@@ -148,8 +148,8 @@ crate enum RegionElement {
     /// a lifetime parameter).
     RootUniversalRegion(RegionVid),
 
-    /// A subuniverse from a subuniverse (e.g., instantiated from a
-    /// `for<'a> fn(&'a u32)` type).
+    /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)`
+    /// type).
     PlaceholderRegion(ty::Placeholder),
 }
 
@@ -252,19 +252,6 @@ impl PlaceholderIndices {
     }
 }
 
-impl ::std::iter::FromIterator<ty::Placeholder> for PlaceholderIndices {
-    fn from_iter<I>(iter: I) -> Self
-    where
-        I: IntoIterator<Item = ty::Placeholder>,
-    {
-        let mut result = Self::default();
-        iter.into_iter().for_each(|p| {
-            result.insert(p);
-        });
-        result
-    }
-}
-
 /// Stores the full values for a set of regions (in contrast to
 /// `LivenessValues`, which only stores those points in the where a
 /// region is live). The full value for a region may contain points in
diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
index 1e279aef07981..96cc1c0afecb4 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
@@ -159,7 +159,7 @@ trait TypeRelatingDelegate<'tcx> {
     fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
 
     /// Creates a new universe index. Used when instantiating placeholders.
-    fn next_subuniverse(&mut self) -> ty::UniverseIndex;
+    fn create_next_universe(&mut self) -> ty::UniverseIndex;
 
     /// Creates a new region variable representing a higher-ranked
     /// region that is instantiated existentially. This creates an
@@ -218,8 +218,8 @@ impl NllTypeRelatingDelegate<'me, 'bccx, 'gcx, 'tcx> {
 }
 
 impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> {
-    fn next_subuniverse(&mut self) -> ty::UniverseIndex {
-        self.infcx.create_subuniverse()
+    fn create_next_universe(&mut self) -> ty::UniverseIndex {
+        self.infcx.create_next_universe()
     }
 
     fn next_existential_region_var(&mut self) -> ty::Region<'tcx> {
@@ -324,7 +324,7 @@ where
                     // new universe for the placeholders we will make
                     // from here out.
                     let universe = lazy_universe.unwrap_or_else(|| {
-                        let universe = delegate.next_subuniverse();
+                        let universe = delegate.create_next_universe();
                         lazy_universe = Some(universe);
                         universe
                     });
diff --git a/src/librustc_traits/chalk_context.rs b/src/librustc_traits/chalk_context.rs
index dea3aa4372a33..536c15234064f 100644
--- a/src/librustc_traits/chalk_context.rs
+++ b/src/librustc_traits/chalk_context.rs
@@ -10,7 +10,9 @@
 
 use chalk_engine::fallible::Fallible as ChalkEngineFallible;
 use chalk_engine::{context, hh::HhGoal, DelayedLiteral, ExClause};
-use rustc::infer::canonical::{Canonical, CanonicalVarValues, QueryRegionConstraint, QueryResult};
+use rustc::infer::canonical::{
+    Canonical, CanonicalVarValues, OriginalQueryValues, QueryRegionConstraint, QueryResponse,
+};
 use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
 use rustc::traits::{
     WellFormed,
@@ -26,7 +28,6 @@ use rustc::traits::{
 use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use rustc::ty::subst::Kind;
 use rustc::ty::{self, TyCtxt};
-use smallvec::SmallVec;
 
 use std::fmt::{self, Debug};
 use std::marker::PhantomData;
@@ -77,7 +78,7 @@ impl context::Context for ChalkArenas<'tcx> {
     // u-canonicalization not yet implemented
     type UniverseMap = UniverseMap;
 
-    type Solution = Canonical<'tcx, QueryResult<'tcx, ()>>;
+    type Solution = Canonical<'tcx, QueryResponse<'tcx, ()>>;
 
     type InferenceNormalizedSubst = CanonicalVarValues<'tcx>;
 
@@ -116,7 +117,7 @@ impl context::AggregateOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
         &self,
         _root_goal: &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>>,
         _simplified_answers: impl context::AnswerStream<ChalkArenas<'gcx>>,
-    ) -> Option<Canonical<'gcx, QueryResult<'gcx, ()>>> {
+    ) -> Option<Canonical<'gcx, QueryResponse<'gcx, ()>>> {
         unimplemented!()
     }
 }
@@ -390,7 +391,7 @@ impl context::UnificationOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
         &mut self,
         value: &ty::ParamEnvAnd<'tcx, Goal<'tcx>>,
     ) -> Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>> {
-        let mut _orig_values = SmallVec::new();
+        let mut _orig_values = OriginalQueryValues::default();
         self.infcx.canonicalize_query(value, &mut _orig_values)
     }
 
diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs
index 2996fe0320042..ed61f07c4d83d 100644
--- a/src/librustc_traits/dropck_outlives.rs
+++ b/src/librustc_traits/dropck_outlives.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use rustc::hir::def_id::DefId;
-use rustc::infer::canonical::{Canonical, QueryResult};
+use rustc::infer::canonical::{Canonical, QueryResponse};
 use rustc::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint};
 use rustc::traits::query::{CanonicalTyGoal, NoSolution};
 use rustc::traits::{FulfillmentContext, Normalized, ObligationCause, TraitEngineExt};
@@ -30,124 +30,125 @@ crate fn provide(p: &mut Providers) {
 
 fn dropck_outlives<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
-    goal: CanonicalTyGoal<'tcx>,
-) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>, NoSolution> {
-    debug!("dropck_outlives(goal={:#?})", goal);
-
-    tcx.infer_ctxt().enter(|ref infcx| {
-        let tcx = infcx.tcx;
-        let (
-            ParamEnvAnd {
+    canonical_goal: CanonicalTyGoal<'tcx>,
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>>, NoSolution> {
+    debug!("dropck_outlives(goal={:#?})", canonical_goal);
+
+    tcx.infer_ctxt().enter_with_canonical(
+        DUMMY_SP,
+        &canonical_goal,
+        |ref infcx, goal, canonical_inference_vars| {
+            let tcx = infcx.tcx;
+            let ParamEnvAnd {
                 param_env,
                 value: for_ty,
-            },
-            canonical_inference_vars,
-        ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
+            } = goal;
 
-        let mut result = DropckOutlivesResult {
-            kinds: vec![],
-            overflows: vec![],
-        };
+            let mut result = DropckOutlivesResult {
+                kinds: vec![],
+                overflows: vec![],
+            };
 
-        // A stack of types left to process. Each round, we pop
-        // something from the stack and invoke
-        // `dtorck_constraint_for_ty`. This may produce new types that
-        // have to be pushed on the stack. This continues until we have explored
-        // all the reachable types from the type `for_ty`.
-        //
-        // Example: Imagine that we have the following code:
-        //
-        // ```rust
-        // struct A {
-        //     value: B,
-        //     children: Vec<A>,
-        // }
-        //
-        // struct B {
-        //     value: u32
-        // }
-        //
-        // fn f() {
-        //   let a: A = ...;
-        //   ..
-        // } // here, `a` is dropped
-        // ```
-        //
-        // at the point where `a` is dropped, we need to figure out
-        // which types inside of `a` contain region data that may be
-        // accessed by any destructors in `a`. We begin by pushing `A`
-        // onto the stack, as that is the type of `a`. We will then
-        // invoke `dtorck_constraint_for_ty` which will expand `A`
-        // into the types of its fields `(B, Vec<A>)`. These will get
-        // pushed onto the stack. Eventually, expanding `Vec<A>` will
-        // lead to us trying to push `A` a second time -- to prevent
-        // infinite recursion, we notice that `A` was already pushed
-        // once and stop.
-        let mut ty_stack = vec![(for_ty, 0)];
-
-        // Set used to detect infinite recursion.
-        let mut ty_set = FxHashSet();
-
-        let fulfill_cx = &mut FulfillmentContext::new();
-
-        let cause = ObligationCause::dummy();
-        while let Some((ty, depth)) = ty_stack.pop() {
-            let DtorckConstraint {
-                dtorck_types,
-                outlives,
-                overflows,
-            } = dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty)?;
-
-            // "outlives" represent types/regions that may be touched
-            // by a destructor.
-            result.kinds.extend(outlives);
-            result.overflows.extend(overflows);
-
-            // dtorck types are "types that will get dropped but which
-            // do not themselves define a destructor", more or less. We have
-            // to push them onto the stack to be expanded.
-            for ty in dtorck_types {
-                match infcx.at(&cause, param_env).normalize(&ty) {
-                    Ok(Normalized {
-                        value: ty,
-                        obligations,
-                    }) => {
-                        fulfill_cx.register_predicate_obligations(infcx, obligations);
-
-                        debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
-
-                        match ty.sty {
-                            // All parameters live for the duration of the
-                            // function.
-                            ty::Param(..) => {}
-
-                            // A projection that we couldn't resolve - it
-                            // might have a destructor.
-                            ty::Projection(..) | ty::Opaque(..) => {
-                                result.kinds.push(ty.into());
-                            }
+            // A stack of types left to process. Each round, we pop
+            // something from the stack and invoke
+            // `dtorck_constraint_for_ty`. This may produce new types that
+            // have to be pushed on the stack. This continues until we have explored
+            // all the reachable types from the type `for_ty`.
+            //
+            // Example: Imagine that we have the following code:
+            //
+            // ```rust
+            // struct A {
+            //     value: B,
+            //     children: Vec<A>,
+            // }
+            //
+            // struct B {
+            //     value: u32
+            // }
+            //
+            // fn f() {
+            //   let a: A = ...;
+            //   ..
+            // } // here, `a` is dropped
+            // ```
+            //
+            // at the point where `a` is dropped, we need to figure out
+            // which types inside of `a` contain region data that may be
+            // accessed by any destructors in `a`. We begin by pushing `A`
+            // onto the stack, as that is the type of `a`. We will then
+            // invoke `dtorck_constraint_for_ty` which will expand `A`
+            // into the types of its fields `(B, Vec<A>)`. These will get
+            // pushed onto the stack. Eventually, expanding `Vec<A>` will
+            // lead to us trying to push `A` a second time -- to prevent
+            // infinite recursion, we notice that `A` was already pushed
+            // once and stop.
+            let mut ty_stack = vec![(for_ty, 0)];
+
+            // Set used to detect infinite recursion.
+            let mut ty_set = FxHashSet();
+
+            let fulfill_cx = &mut FulfillmentContext::new();
+
+            let cause = ObligationCause::dummy();
+            while let Some((ty, depth)) = ty_stack.pop() {
+                let DtorckConstraint {
+                    dtorck_types,
+                    outlives,
+                    overflows,
+                } = dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty)?;
+
+                // "outlives" represent types/regions that may be touched
+                // by a destructor.
+                result.kinds.extend(outlives);
+                result.overflows.extend(overflows);
+
+                // dtorck types are "types that will get dropped but which
+                // do not themselves define a destructor", more or less. We have
+                // to push them onto the stack to be expanded.
+                for ty in dtorck_types {
+                    match infcx.at(&cause, param_env).normalize(&ty) {
+                        Ok(Normalized {
+                            value: ty,
+                            obligations,
+                        }) => {
+                            fulfill_cx.register_predicate_obligations(infcx, obligations);
+
+                            debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
+
+                            match ty.sty {
+                                // All parameters live for the duration of the
+                                // function.
+                                ty::Param(..) => {}
+
+                                // A projection that we couldn't resolve - it
+                                // might have a destructor.
+                                ty::Projection(..) | ty::Opaque(..) => {
+                                    result.kinds.push(ty.into());
+                                }
 
-                            _ => {
-                                if ty_set.insert(ty) {
-                                    ty_stack.push((ty, depth + 1));
+                                _ => {
+                                    if ty_set.insert(ty) {
+                                        ty_stack.push((ty, depth + 1));
+                                    }
                                 }
                             }
                         }
-                    }
 
-                    // We don't actually expect to fail to normalize.
-                    // That implies a WF error somewhere else.
-                    Err(NoSolution) => {
-                        return Err(NoSolution);
+                        // We don't actually expect to fail to normalize.
+                        // That implies a WF error somewhere else.
+                        Err(NoSolution) => {
+                            return Err(NoSolution);
+                        }
                     }
                 }
             }
-        }
 
-        debug!("dropck_outlives: result = {:#?}", result);
+            debug!("dropck_outlives: result = {:#?}", result);
 
-        infcx.make_canonicalized_query_result(canonical_inference_vars, result, fulfill_cx)
-    })
+            infcx.make_canonicalized_query_response(canonical_inference_vars, result, fulfill_cx)
+        },
+    )
 }
 
 /// Return a set of constraints that needs to be satisfied in
@@ -195,8 +196,7 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>(
             dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety)
         }
 
-        ty::Tuple(tys) => tys
-            .iter()
+        ty::Tuple(tys) => tys.iter()
             .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
             .collect(),
 
@@ -308,8 +308,7 @@ crate fn adt_dtorck_constraint<'a, 'tcx>(
         return Ok(result);
     }
 
-    let mut result = def
-        .all_fields()
+    let mut result = def.all_fields()
         .map(|field| tcx.type_of(field.did))
         .map(|fty| dtorck_constraint_for_ty(tcx, span, fty, 0, fty))
         .collect::<Result<DtorckConstraint, NoSolution>>()?;
diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs
index b5ee346569a69..15ef1106311b3 100644
--- a/src/librustc_traits/evaluate_obligation.rs
+++ b/src/librustc_traits/evaluate_obligation.rs
@@ -8,9 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::traits::{EvaluationResult, Obligation, ObligationCause,
-                    OverflowError, SelectionContext, TraitQueryMode};
 use rustc::traits::query::CanonicalPredicateGoal;
+use rustc::traits::{
+    EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode,
+};
 use rustc::ty::query::Providers;
 use rustc::ty::{ParamEnvAnd, TyCtxt};
 use syntax::source_map::DUMMY_SP;
@@ -24,20 +25,21 @@ crate fn provide(p: &mut Providers) {
 
 fn evaluate_obligation<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
-    goal: CanonicalPredicateGoal<'tcx>,
+    canonical_goal: CanonicalPredicateGoal<'tcx>,
 ) -> Result<EvaluationResult, OverflowError> {
-    tcx.infer_ctxt().enter(|ref infcx| {
-        let (
-            ParamEnvAnd {
+    tcx.infer_ctxt().enter_with_canonical(
+        DUMMY_SP,
+        &canonical_goal,
+        |ref infcx, goal, _canonical_inference_vars| {
+            let ParamEnvAnd {
                 param_env,
                 value: predicate,
-            },
-            _canonical_inference_vars,
-        ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
+            } = goal;
 
-        let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
-        let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
+            let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
+            let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
 
-        selcx.evaluate_obligation_recursively(&obligation)
-    })
+            selcx.evaluate_obligation_recursively(&obligation)
+        },
+    )
 }
diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs
index 7b31518c07b18..ad0a54e392f58 100644
--- a/src/librustc_traits/implied_outlives_bounds.rs
+++ b/src/librustc_traits/implied_outlives_bounds.rs
@@ -37,7 +37,7 @@ fn implied_outlives_bounds<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     goal: CanonicalTyGoal<'tcx>,
 ) -> Result<
-        Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, Vec<OutlivesBound<'tcx>>>>>,
+        Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>>,
         NoSolution,
 > {
     tcx.infer_ctxt()
diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs
index 1c0f677fbf3cb..637a50728f39c 100644
--- a/src/librustc_traits/normalize_projection_ty.rs
+++ b/src/librustc_traits/normalize_projection_ty.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::infer::canonical::{Canonical, QueryResult};
+use rustc::infer::canonical::{Canonical, QueryResponse};
 use rustc::traits::query::{normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution};
 use rustc::traits::{self, ObligationCause, SelectionContext, TraitEngineExt};
 use rustc::ty::query::Providers;
@@ -28,7 +28,7 @@ crate fn provide(p: &mut Providers) {
 fn normalize_projection_ty<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     goal: CanonicalProjectionGoal<'tcx>,
-) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, NormalizationResult<'tcx>>>>, NoSolution> {
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>>, NoSolution> {
     debug!("normalize_provider(goal={:#?})", goal);
 
     tcx.sess
diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs
index 8fe4290528e74..a857cdbda45ae 100644
--- a/src/librustc_traits/type_op.rs
+++ b/src/librustc_traits/type_op.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::infer::canonical::{Canonical, QueryResult};
+use rustc::infer::canonical::{Canonical, QueryResponse};
 use rustc::infer::InferCtxt;
 use rustc::traits::query::type_op::eq::Eq;
 use rustc::traits::query::type_op::normalize::Normalize;
@@ -38,7 +38,7 @@ crate fn provide(p: &mut Providers) {
 fn type_op_eq<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>,
-) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, ()>>>, NoSolution> {
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>, NoSolution> {
     tcx.infer_ctxt()
         .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
             let (param_env, Eq { a, b }) = key.into_parts();
@@ -68,7 +68,7 @@ where
 fn type_op_normalize_ty(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Ty<'tcx>>>>,
-) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, Ty<'tcx>>>>, NoSolution> {
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>>, NoSolution> {
     tcx.infer_ctxt()
         .enter_canonical_trait_query(&canonicalized, type_op_normalize)
 }
@@ -76,7 +76,7 @@ fn type_op_normalize_ty(
 fn type_op_normalize_predicate(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Predicate<'tcx>>>>,
-) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, Predicate<'tcx>>>>, NoSolution> {
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, Predicate<'tcx>>>>, NoSolution> {
     tcx.infer_ctxt()
         .enter_canonical_trait_query(&canonicalized, type_op_normalize)
 }
@@ -84,7 +84,7 @@ fn type_op_normalize_predicate(
 fn type_op_normalize_fn_sig(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<FnSig<'tcx>>>>,
-) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, FnSig<'tcx>>>>, NoSolution> {
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, FnSig<'tcx>>>>, NoSolution> {
     tcx.infer_ctxt()
         .enter_canonical_trait_query(&canonicalized, type_op_normalize)
 }
@@ -92,7 +92,7 @@ fn type_op_normalize_fn_sig(
 fn type_op_normalize_poly_fn_sig(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<PolyFnSig<'tcx>>>>,
-) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, PolyFnSig<'tcx>>>>, NoSolution> {
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, PolyFnSig<'tcx>>>>, NoSolution> {
     tcx.infer_ctxt()
         .enter_canonical_trait_query(&canonicalized, type_op_normalize)
 }
@@ -100,7 +100,7 @@ fn type_op_normalize_poly_fn_sig(
 fn type_op_subtype<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Subtype<'tcx>>>,
-) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, ()>>>, NoSolution> {
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>, NoSolution> {
     tcx.infer_ctxt()
         .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
             let (param_env, Subtype { sub, sup }) = key.into_parts();
@@ -114,7 +114,7 @@ fn type_op_subtype<'tcx>(
 fn type_op_prove_predicate<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>,
-) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, ()>>>, NoSolution> {
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>, NoSolution> {
     tcx.infer_ctxt()
         .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
             let (param_env, ProvePredicate { predicate }) = key.into_parts();