From 42eb7032fab11aca9228d42969f471b581444c56 Mon Sep 17 00:00:00 2001
From: Eduard Burtescu <edy.burt@gmail.com>
Date: Wed, 11 May 2016 08:48:12 +0300
Subject: [PATCH] Fixup indentation after methodification.

---
 src/librustc/infer/combine.rs               |  170 +-
 src/librustc/infer/higher_ranked/mod.rs     |  304 +-
 src/librustc/infer/mod.rs                   |   82 +-
 src/librustc/middle/astconv_util.rs         |  108 +-
 src/librustc/middle/stability.rs            |   62 +-
 src/librustc/traits/error_reporting.rs      | 1614 ++++-----
 src/librustc/traits/object_safety.rs        |  592 +--
 src/librustc/traits/util.rs                 |  240 +-
 src/librustc/ty/outlives.rs                 |  272 +-
 src/librustc_typeck/astconv.rs              | 3557 ++++++++++---------
 src/librustc_typeck/check/_match.rs         | 1376 +++----
 src/librustc_typeck/check/callee.rs         |  468 +--
 src/librustc_typeck/check/cast.rs           |   32 +-
 src/librustc_typeck/check/closure.rs        |  412 +--
 src/librustc_typeck/check/coercion.rs       |  284 +-
 src/librustc_typeck/check/demand.rs         |   94 +-
 src/librustc_typeck/check/method/confirm.rs |   32 +-
 src/librustc_typeck/check/method/mod.rs     |  555 +--
 src/librustc_typeck/check/method/probe.rs   |  190 +-
 src/librustc_typeck/check/method/suggest.rs |  658 ++--
 src/librustc_typeck/check/mod.rs            | 3282 ++++++++---------
 src/librustc_typeck/check/op.rs             |  601 ++--
 src/librustc_typeck/check/regionck.rs       | 2472 ++++++-------
 src/librustc_typeck/check/upvar.rs          |   49 +-
 src/librustc_typeck/check/wfcheck.rs        |   68 +-
 src/librustc_typeck/check/writeback.rs      |   56 +-
 src/librustc_typeck/coherence/mod.rs        |   54 +-
 27 files changed, 8859 insertions(+), 8825 deletions(-)

diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 3ee034cb09e..e2f27074dbf 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -61,95 +61,95 @@ pub struct CombineFields<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-pub fn super_combine_tys<R>(&self,
-                            relation: &mut R,
-                            a: Ty<'tcx>,
-                            b: Ty<'tcx>)
+    pub fn super_combine_tys<R>(&self,
+                                relation: &mut R,
+                                a: Ty<'tcx>,
+                                b: Ty<'tcx>)
+                                -> RelateResult<'tcx, Ty<'tcx>>
+        where R: TypeRelation<'a, 'gcx, 'tcx>
+    {
+        let a_is_expected = relation.a_is_expected();
+
+        match (&a.sty, &b.sty) {
+            // Relate integral variables to other types
+            (&ty::TyInfer(ty::IntVar(a_id)), &ty::TyInfer(ty::IntVar(b_id))) => {
+                self.int_unification_table
+                    .borrow_mut()
+                    .unify_var_var(a_id, b_id)
+                    .map_err(|e| int_unification_error(a_is_expected, e))?;
+                Ok(a)
+            }
+            (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyInt(v)) => {
+                self.unify_integral_variable(a_is_expected, v_id, IntType(v))
+            }
+            (&ty::TyInt(v), &ty::TyInfer(ty::IntVar(v_id))) => {
+                self.unify_integral_variable(!a_is_expected, v_id, IntType(v))
+            }
+            (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyUint(v)) => {
+                self.unify_integral_variable(a_is_expected, v_id, UintType(v))
+            }
+            (&ty::TyUint(v), &ty::TyInfer(ty::IntVar(v_id))) => {
+                self.unify_integral_variable(!a_is_expected, v_id, UintType(v))
+            }
+
+            // Relate floating-point variables to other types
+            (&ty::TyInfer(ty::FloatVar(a_id)), &ty::TyInfer(ty::FloatVar(b_id))) => {
+                self.float_unification_table
+                    .borrow_mut()
+                    .unify_var_var(a_id, b_id)
+                    .map_err(|e| float_unification_error(relation.a_is_expected(), e))?;
+                Ok(a)
+            }
+            (&ty::TyInfer(ty::FloatVar(v_id)), &ty::TyFloat(v)) => {
+                self.unify_float_variable(a_is_expected, v_id, v)
+            }
+            (&ty::TyFloat(v), &ty::TyInfer(ty::FloatVar(v_id))) => {
+                self.unify_float_variable(!a_is_expected, v_id, v)
+            }
+
+            // All other cases of inference are errors
+            (&ty::TyInfer(_), _) |
+            (_, &ty::TyInfer(_)) => {
+                Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b)))
+            }
+
+
+            _ => {
+                ty::relate::super_relate_tys(relation, a, b)
+            }
+        }
+    }
+
+    fn unify_integral_variable(&self,
+                               vid_is_expected: bool,
+                               vid: ty::IntVid,
+                               val: ty::IntVarValue)
+                               -> RelateResult<'tcx, Ty<'tcx>>
+    {
+        self.int_unification_table
+            .borrow_mut()
+            .unify_var_value(vid, val)
+            .map_err(|e| int_unification_error(vid_is_expected, e))?;
+        match val {
+            IntType(v) => Ok(self.tcx.mk_mach_int(v)),
+            UintType(v) => Ok(self.tcx.mk_mach_uint(v)),
+        }
+    }
+
+    fn unify_float_variable(&self,
+                            vid_is_expected: bool,
+                            vid: ty::FloatVid,
+                            val: ast::FloatTy)
                             -> RelateResult<'tcx, Ty<'tcx>>
-    where R: TypeRelation<'a, 'gcx, 'tcx>
-{
-    let a_is_expected = relation.a_is_expected();
-
-    match (&a.sty, &b.sty) {
-        // Relate integral variables to other types
-        (&ty::TyInfer(ty::IntVar(a_id)), &ty::TyInfer(ty::IntVar(b_id))) => {
-            self.int_unification_table
-                .borrow_mut()
-                .unify_var_var(a_id, b_id)
-                .map_err(|e| int_unification_error(a_is_expected, e))?;
-            Ok(a)
-        }
-        (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyInt(v)) => {
-            self.unify_integral_variable(a_is_expected, v_id, IntType(v))
-        }
-        (&ty::TyInt(v), &ty::TyInfer(ty::IntVar(v_id))) => {
-            self.unify_integral_variable(!a_is_expected, v_id, IntType(v))
-        }
-        (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyUint(v)) => {
-            self.unify_integral_variable(a_is_expected, v_id, UintType(v))
-        }
-        (&ty::TyUint(v), &ty::TyInfer(ty::IntVar(v_id))) => {
-            self.unify_integral_variable(!a_is_expected, v_id, UintType(v))
-        }
-
-        // Relate floating-point variables to other types
-        (&ty::TyInfer(ty::FloatVar(a_id)), &ty::TyInfer(ty::FloatVar(b_id))) => {
-            self.float_unification_table
-                .borrow_mut()
-                .unify_var_var(a_id, b_id)
-                .map_err(|e| float_unification_error(relation.a_is_expected(), e))?;
-            Ok(a)
-        }
-        (&ty::TyInfer(ty::FloatVar(v_id)), &ty::TyFloat(v)) => {
-            self.unify_float_variable(a_is_expected, v_id, v)
-        }
-        (&ty::TyFloat(v), &ty::TyInfer(ty::FloatVar(v_id))) => {
-            self.unify_float_variable(!a_is_expected, v_id, v)
-        }
-
-        // All other cases of inference are errors
-        (&ty::TyInfer(_), _) |
-        (_, &ty::TyInfer(_)) => {
-            Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b)))
-        }
-
-
-        _ => {
-            ty::relate::super_relate_tys(relation, a, b)
-        }
+    {
+        self.float_unification_table
+            .borrow_mut()
+            .unify_var_value(vid, val)
+            .map_err(|e| float_unification_error(vid_is_expected, e))?;
+        Ok(self.tcx.mk_mach_float(val))
     }
 }
 
-fn unify_integral_variable(&self,
-                           vid_is_expected: bool,
-                           vid: ty::IntVid,
-                           val: ty::IntVarValue)
-                           -> RelateResult<'tcx, Ty<'tcx>>
-{
-    self.int_unification_table
-        .borrow_mut()
-        .unify_var_value(vid, val)
-        .map_err(|e| int_unification_error(vid_is_expected, e))?;
-    match val {
-        IntType(v) => Ok(self.tcx.mk_mach_int(v)),
-        UintType(v) => Ok(self.tcx.mk_mach_uint(v)),
-    }
-}
-
-fn unify_float_variable(&self,
-                        vid_is_expected: bool,
-                        vid: ty::FloatVid,
-                        val: ast::FloatTy)
-                        -> RelateResult<'tcx, Ty<'tcx>>
-{
-    self.float_unification_table
-        .borrow_mut()
-        .unify_var_value(vid, val)
-        .map_err(|e| float_unification_error(vid_is_expected, e))?;
-    Ok(self.tcx.mk_mach_float(val))
-}
-}
-
 impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
     pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
         self.infcx.tcx
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index 63d462b9f4f..6814d50107f 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -422,169 +422,169 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         region_vars
     }
 
-pub fn skolemize_late_bound_regions<T>(&self,
-                                       binder: &ty::Binder<T>,
-                                       snapshot: &CombinedSnapshot)
-                                       -> (T, SkolemizationMap)
-    where T : TypeFoldable<'tcx>
-{
-    /*!
-     * Replace all regions bound by `binder` with skolemized regions and
-     * return a map indicating which bound-region was replaced with what
-     * skolemized region. This is the first step of checking subtyping
-     * when higher-ranked things are involved. See `README.md` for more
-     * details.
-     */
+    pub fn skolemize_late_bound_regions<T>(&self,
+                                           binder: &ty::Binder<T>,
+                                           snapshot: &CombinedSnapshot)
+                                           -> (T, SkolemizationMap)
+        where T : TypeFoldable<'tcx>
+    {
+        /*!
+         * Replace all regions bound by `binder` with skolemized regions and
+         * return a map indicating which bound-region was replaced with what
+         * skolemized region. This is the first step of checking subtyping
+         * when higher-ranked things are involved. See `README.md` for more
+         * details.
+         */
 
-    let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
-        self.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot)
-    });
+        let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
+            self.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot)
+        });
 
-    debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})",
-           binder,
-           result,
-           map);
+        debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})",
+               binder,
+               result,
+               map);
 
-    (result, map)
-}
-
-pub fn leak_check(&self,
-                  overly_polymorphic: bool,
-                  skol_map: &SkolemizationMap,
-                  snapshot: &CombinedSnapshot)
-                  -> RelateResult<'tcx, ()>
-{
-    /*!
-     * Searches the region constriants created since `snapshot` was started
-     * and checks to determine whether any of the skolemized regions created
-     * in `skol_map` would "escape" -- meaning that they are related to
-     * other regions in some way. If so, the higher-ranked subtyping doesn't
-     * hold. See `README.md` for more details.
-     */
-
-    debug!("leak_check: skol_map={:?}",
-           skol_map);
-
-    let new_vars = self.region_vars_confined_to_snapshot(snapshot);
-    for (&skol_br, &skol) in skol_map {
-        let tainted = self.tainted_regions(snapshot, skol);
-        for &tainted_region in &tainted {
-            // Each skolemized should only be relatable to itself
-            // or new variables:
-            match tainted_region {
-                ty::ReVar(vid) => {
-                    if new_vars.iter().any(|&x| x == vid) { continue; }
-                }
-                _ => {
-                    if tainted_region == skol { continue; }
-                }
-            };
-
-            debug!("{:?} (which replaced {:?}) is tainted by {:?}",
-                   skol,
-                   skol_br,
-                   tainted_region);
-
-            if overly_polymorphic {
-                debug!("Overly polymorphic!");
-                return Err(TypeError::RegionsOverlyPolymorphic(skol_br,
-                                                               tainted_region));
-            } else {
-                debug!("Not as polymorphic!");
-                return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br,
-                                                                       tainted_region));
-            }
-        }
+        (result, map)
     }
-    Ok(())
-}
 
-/// This code converts from skolemized regions back to late-bound
-/// regions. It works by replacing each region in the taint set of a
-/// skolemized region with a bound-region. The bound region will be bound
-/// by the outer-most binder in `value`; the caller must ensure that there is
-/// such a binder and it is the right place.
-///
-/// This routine is only intended to be used when the leak-check has
-/// passed; currently, it's used in the trait matching code to create
-/// a set of nested obligations frmo an impl that matches against
-/// something higher-ranked.  More details can be found in
-/// `librustc/middle/traits/README.md`.
-///
-/// As a brief example, consider the obligation `for<'a> Fn(&'a int)
-/// -> &'a int`, and the impl:
-///
-///     impl<A,R> Fn<A,R> for SomethingOrOther
-///         where A : Clone
-///     { ... }
-///
-/// Here we will have replaced `'a` with a skolemized region
-/// `'0`. This means that our substitution will be `{A=>&'0
-/// int, R=>&'0 int}`.
-///
-/// When we apply the substitution to the bounds, we will wind up with
-/// `&'0 int : Clone` as a predicate. As a last step, we then go and
-/// replace `'0` with a late-bound region `'a`.  The depth is matched
-/// to the depth of the predicate, in this case 1, so that the final
-/// predicate is `for<'a> &'a int : Clone`.
-pub fn plug_leaks<T>(&self,
-                     skol_map: SkolemizationMap,
-                     snapshot: &CombinedSnapshot,
-                     value: &T) -> T
-    where T : TypeFoldable<'tcx>
-{
-    debug_assert!(self.leak_check(false, &skol_map, snapshot).is_ok());
+    pub fn leak_check(&self,
+                      overly_polymorphic: bool,
+                      skol_map: &SkolemizationMap,
+                      snapshot: &CombinedSnapshot)
+                      -> RelateResult<'tcx, ()>
+    {
+        /*!
+         * Searches the region constriants created since `snapshot` was started
+         * and checks to determine whether any of the skolemized regions created
+         * in `skol_map` would "escape" -- meaning that they are related to
+         * other regions in some way. If so, the higher-ranked subtyping doesn't
+         * hold. See `README.md` for more details.
+         */
 
-    debug!("plug_leaks(skol_map={:?}, value={:?})",
-           skol_map,
-           value);
+        debug!("leak_check: skol_map={:?}",
+               skol_map);
 
-    // Compute a mapping from the "taint set" of each skolemized
-    // region back to the `ty::BoundRegion` that it originally
-    // represented. Because `leak_check` passed, we know that
-    // these taint sets are mutually disjoint.
-    let inv_skol_map: FnvHashMap<ty::Region, ty::BoundRegion> =
-        skol_map
-        .into_iter()
-        .flat_map(|(skol_br, skol)| {
-            self.tainted_regions(snapshot, skol)
-                .into_iter()
-                .map(move |tainted_region| (tainted_region, skol_br))
-        })
-        .collect();
+        let new_vars = self.region_vars_confined_to_snapshot(snapshot);
+        for (&skol_br, &skol) in skol_map {
+            let tainted = self.tainted_regions(snapshot, skol);
+            for &tainted_region in &tainted {
+                // Each skolemized should only be relatable to itself
+                // or new variables:
+                match tainted_region {
+                    ty::ReVar(vid) => {
+                        if new_vars.iter().any(|&x| x == vid) { continue; }
+                    }
+                    _ => {
+                        if tainted_region == skol { continue; }
+                    }
+                };
 
-    debug!("plug_leaks: inv_skol_map={:?}",
-           inv_skol_map);
+                debug!("{:?} (which replaced {:?}) is tainted by {:?}",
+                       skol,
+                       skol_br,
+                       tainted_region);
 
-    // Remove any instantiated type variables from `value`; those can hide
-    // references to regions from the `fold_regions` code below.
-    let value = self.resolve_type_vars_if_possible(value);
-
-    // Map any skolemization byproducts back to a late-bound
-    // region. Put that late-bound region at whatever the outermost
-    // binder is that we encountered in `value`. The caller is
-    // responsible for ensuring that (a) `value` contains at least one
-    // binder and (b) that binder is the one we want to use.
-    let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| {
-        match inv_skol_map.get(&r) {
-            None => r,
-            Some(br) => {
-                // It is the responsibility of the caller to ensure
-                // that each skolemized region appears within a
-                // binder. In practice, this routine is only used by
-                // trait checking, and all of the skolemized regions
-                // appear inside predicates, which always have
-                // binders, so this assert is satisfied.
-                assert!(current_depth > 1);
-
-                ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone())
+                if overly_polymorphic {
+                    debug!("Overly polymorphic!");
+                    return Err(TypeError::RegionsOverlyPolymorphic(skol_br,
+                                                                   tainted_region));
+                } else {
+                    debug!("Not as polymorphic!");
+                    return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br,
+                                                                           tainted_region));
+                }
             }
         }
-    });
+        Ok(())
+    }
 
-    debug!("plug_leaks: result={:?}",
-           result);
+    /// This code converts from skolemized regions back to late-bound
+    /// regions. It works by replacing each region in the taint set of a
+    /// skolemized region with a bound-region. The bound region will be bound
+    /// by the outer-most binder in `value`; the caller must ensure that there is
+    /// such a binder and it is the right place.
+    ///
+    /// This routine is only intended to be used when the leak-check has
+    /// passed; currently, it's used in the trait matching code to create
+    /// a set of nested obligations frmo an impl that matches against
+    /// something higher-ranked.  More details can be found in
+    /// `librustc/middle/traits/README.md`.
+    ///
+    /// As a brief example, consider the obligation `for<'a> Fn(&'a int)
+    /// -> &'a int`, and the impl:
+    ///
+    ///     impl<A,R> Fn<A,R> for SomethingOrOther
+    ///         where A : Clone
+    ///     { ... }
+    ///
+    /// Here we will have replaced `'a` with a skolemized region
+    /// `'0`. This means that our substitution will be `{A=>&'0
+    /// int, R=>&'0 int}`.
+    ///
+    /// When we apply the substitution to the bounds, we will wind up with
+    /// `&'0 int : Clone` as a predicate. As a last step, we then go and
+    /// replace `'0` with a late-bound region `'a`.  The depth is matched
+    /// to the depth of the predicate, in this case 1, so that the final
+    /// predicate is `for<'a> &'a int : Clone`.
+    pub fn plug_leaks<T>(&self,
+                         skol_map: SkolemizationMap,
+                         snapshot: &CombinedSnapshot,
+                         value: &T) -> T
+        where T : TypeFoldable<'tcx>
+    {
+        debug_assert!(self.leak_check(false, &skol_map, snapshot).is_ok());
 
-    result
-}
+        debug!("plug_leaks(skol_map={:?}, value={:?})",
+               skol_map,
+               value);
+
+        // Compute a mapping from the "taint set" of each skolemized
+        // region back to the `ty::BoundRegion` that it originally
+        // represented. Because `leak_check` passed, we know that
+        // these taint sets are mutually disjoint.
+        let inv_skol_map: FnvHashMap<ty::Region, ty::BoundRegion> =
+            skol_map
+            .into_iter()
+            .flat_map(|(skol_br, skol)| {
+                self.tainted_regions(snapshot, skol)
+                    .into_iter()
+                    .map(move |tainted_region| (tainted_region, skol_br))
+            })
+            .collect();
+
+        debug!("plug_leaks: inv_skol_map={:?}",
+               inv_skol_map);
+
+        // Remove any instantiated type variables from `value`; those can hide
+        // references to regions from the `fold_regions` code below.
+        let value = self.resolve_type_vars_if_possible(value);
+
+        // Map any skolemization byproducts back to a late-bound
+        // region. Put that late-bound region at whatever the outermost
+        // binder is that we encountered in `value`. The caller is
+        // responsible for ensuring that (a) `value` contains at least one
+        // binder and (b) that binder is the one we want to use.
+        let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| {
+            match inv_skol_map.get(&r) {
+                None => r,
+                Some(br) => {
+                    // It is the responsibility of the caller to ensure
+                    // that each skolemized region appears within a
+                    // binder. In practice, this routine is only used by
+                    // trait checking, and all of the skolemized regions
+                    // appear inside predicates, which always have
+                    // binders, so this assert is satisfied.
+                    assert!(current_depth > 1);
+
+                    ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone())
+                }
+            }
+        });
+
+        debug!("plug_leaks: result={:?}",
+               result);
+
+        result
+    }
 }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index fe9e128d8a6..29d8a808de5 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -628,53 +628,53 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
     }
 
-pub fn drain_fulfillment_cx_or_panic<T>(&self,
-                                        span: Span,
-                                        fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
-                                        result: &T)
-                                        -> T::Lifted
-    where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
-{
-    let when = "resolving bounds after type-checking";
-    let v = match self.drain_fulfillment_cx(fulfill_cx, result) {
-        Ok(v) => v,
-        Err(errors) => {
-            span_bug!(span, "Encountered errors `{:?}` {}", errors, when);
-        }
-    };
+    pub fn drain_fulfillment_cx_or_panic<T>(&self,
+                                            span: Span,
+                                            fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
+                                            result: &T)
+                                            -> T::Lifted
+        where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
+    {
+        let when = "resolving bounds after type-checking";
+        let v = match self.drain_fulfillment_cx(fulfill_cx, result) {
+            Ok(v) => v,
+            Err(errors) => {
+                span_bug!(span, "Encountered errors `{:?}` {}", errors, when);
+            }
+        };
 
-    match self.tcx.lift_to_global(&v) {
-        Some(v) => v,
-        None => {
-            span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when);
+        match self.tcx.lift_to_global(&v) {
+            Some(v) => v,
+            None => {
+                span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when);
+            }
         }
     }
-}
 
-/// Finishes processes any obligations that remain in the fulfillment
-/// context, and then "freshens" and returns `result`. This is
-/// primarily used during normalization and other cases where
-/// processing the obligations in `fulfill_cx` may cause type
-/// inference variables that appear in `result` to be unified, and
-/// hence we need to process those obligations to get the complete
-/// picture of the type.
-pub fn drain_fulfillment_cx<T>(&self,
-                               fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
-                               result: &T)
-                               -> Result<T,Vec<traits::FulfillmentError<'tcx>>>
-    where T : TypeFoldable<'tcx>
-{
-    debug!("drain_fulfillment_cx(result={:?})",
-           result);
+    /// Finishes processes any obligations that remain in the fulfillment
+    /// context, and then "freshens" and returns `result`. This is
+    /// primarily used during normalization and other cases where
+    /// processing the obligations in `fulfill_cx` may cause type
+    /// inference variables that appear in `result` to be unified, and
+    /// hence we need to process those obligations to get the complete
+    /// picture of the type.
+    pub fn drain_fulfillment_cx<T>(&self,
+                                   fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
+                                   result: &T)
+                                   -> Result<T,Vec<traits::FulfillmentError<'tcx>>>
+        where T : TypeFoldable<'tcx>
+    {
+        debug!("drain_fulfillment_cx(result={:?})",
+               result);
 
-    // In principle, we only need to do this so long as `result`
-    // contains unbound type parameters. It could be a slight
-    // optimization to stop iterating early.
-    fulfill_cx.select_all_or_error(self)?;
+        // In principle, we only need to do this so long as `result`
+        // contains unbound type parameters. It could be a slight
+        // optimization to stop iterating early.
+        fulfill_cx.select_all_or_error(self)?;
 
-    let result = self.resolve_type_vars_if_possible(result);
-    Ok(self.tcx.erase_regions(&result))
-}
+        let result = self.resolve_type_vars_if_possible(result);
+        Ok(self.tcx.erase_regions(&result))
+    }
 
     pub fn projection_mode(&self) -> ProjectionMode {
         self.projection_mode
diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs
index 4129c53c988..8f97a89e654 100644
--- a/src/librustc/middle/astconv_util.rs
+++ b/src/librustc/middle/astconv_util.rs
@@ -21,63 +21,63 @@ use syntax::codemap::Span;
 use hir as ast;
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-pub fn prohibit_type_params(self, segments: &[ast::PathSegment]) {
-    for segment in segments {
-        for typ in segment.parameters.types() {
-            span_err!(self.sess, typ.span, E0109,
-                      "type parameters are not allowed on this type");
-            break;
-        }
-        for lifetime in segment.parameters.lifetimes() {
-            span_err!(self.sess, lifetime.span, E0110,
-                      "lifetime parameters are not allowed on this type");
-            break;
-        }
-        for binding in segment.parameters.bindings() {
-            self.prohibit_projection(binding.span);
-            break;
-        }
-    }
-}
-
-pub fn prohibit_projection(self, span: Span)
-{
-    span_err!(self.sess, span, E0229,
-              "associated type bindings are not allowed here");
-}
-
-pub fn prim_ty_to_ty(self,
-                     segments: &[ast::PathSegment],
-                     nty: ast::PrimTy)
-                     -> Ty<'tcx> {
-    self.prohibit_type_params(segments);
-    match nty {
-        ast::TyBool => self.types.bool,
-        ast::TyChar => self.types.char,
-        ast::TyInt(it) => self.mk_mach_int(it),
-        ast::TyUint(uit) => self.mk_mach_uint(uit),
-        ast::TyFloat(ft) => self.mk_mach_float(ft),
-        ast::TyStr => self.mk_str()
-    }
-}
-
-/// If a type in the AST is a primitive type, return the ty::Ty corresponding
-/// to it.
-pub fn ast_ty_to_prim_ty(self, ast_ty: &ast::Ty) -> Option<Ty<'tcx>> {
-    if let ast::TyPath(None, ref path) = ast_ty.node {
-        let def = match self.def_map.borrow().get(&ast_ty.id) {
-            None => {
-                span_bug!(ast_ty.span, "unbound path {:?}", path)
+    pub fn prohibit_type_params(self, segments: &[ast::PathSegment]) {
+        for segment in segments {
+            for typ in segment.parameters.types() {
+                span_err!(self.sess, typ.span, E0109,
+                          "type parameters are not allowed on this type");
+                break;
+            }
+            for lifetime in segment.parameters.lifetimes() {
+                span_err!(self.sess, lifetime.span, E0110,
+                          "lifetime parameters are not allowed on this type");
+                break;
+            }
+            for binding in segment.parameters.bindings() {
+                self.prohibit_projection(binding.span);
+                break;
+            }
+        }
+    }
+
+    pub fn prohibit_projection(self, span: Span)
+    {
+        span_err!(self.sess, span, E0229,
+                  "associated type bindings are not allowed here");
+    }
+
+    pub fn prim_ty_to_ty(self,
+                         segments: &[ast::PathSegment],
+                         nty: ast::PrimTy)
+                         -> Ty<'tcx> {
+        self.prohibit_type_params(segments);
+        match nty {
+            ast::TyBool => self.types.bool,
+            ast::TyChar => self.types.char,
+            ast::TyInt(it) => self.mk_mach_int(it),
+            ast::TyUint(uit) => self.mk_mach_uint(uit),
+            ast::TyFloat(ft) => self.mk_mach_float(ft),
+            ast::TyStr => self.mk_str()
+        }
+    }
+
+    /// If a type in the AST is a primitive type, return the ty::Ty corresponding
+    /// to it.
+    pub fn ast_ty_to_prim_ty(self, ast_ty: &ast::Ty) -> Option<Ty<'tcx>> {
+        if let ast::TyPath(None, ref path) = ast_ty.node {
+            let def = match self.def_map.borrow().get(&ast_ty.id) {
+                None => {
+                    span_bug!(ast_ty.span, "unbound path {:?}", path)
+                }
+                Some(d) => d.full_def()
+            };
+            if let Def::PrimTy(nty) = def {
+                Some(self.prim_ty_to_ty(&path.segments, nty))
+            } else {
+                None
             }
-            Some(d) => d.full_def()
-        };
-        if let Def::PrimTy(nty) = def {
-            Some(self.prim_ty_to_ty(&path.segments, nty))
         } else {
             None
         }
-    } else {
-        None
     }
 }
-}
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 9fabdf58b6f..c2db6de0370 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -670,46 +670,46 @@ fn is_staged_api<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> bool {
 }
 
 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
-/// Lookup the stability for a node, loading external crate
-/// metadata as necessary.
-pub fn lookup_stability(self, id: DefId) -> Option<&'tcx Stability> {
-    if let Some(st) = self.stability.borrow().stab_map.get(&id) {
-        return *st;
+    /// Lookup the stability for a node, loading external crate
+    /// metadata as necessary.
+    pub fn lookup_stability(self, id: DefId) -> Option<&'tcx Stability> {
+        if let Some(st) = self.stability.borrow().stab_map.get(&id) {
+            return *st;
+        }
+
+        let st = self.lookup_stability_uncached(id);
+        self.stability.borrow_mut().stab_map.insert(id, st);
+        st
     }
 
-    let st = self.lookup_stability_uncached(id);
-    self.stability.borrow_mut().stab_map.insert(id, st);
-    st
-}
+    pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
+        if let Some(depr) = self.stability.borrow().depr_map.get(&id) {
+            return depr.clone();
+        }
 
-pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
-    if let Some(depr) = self.stability.borrow().depr_map.get(&id) {
-        return depr.clone();
+        let depr = self.lookup_deprecation_uncached(id);
+        self.stability.borrow_mut().depr_map.insert(id, depr.clone());
+        depr
     }
 
-    let depr = self.lookup_deprecation_uncached(id);
-    self.stability.borrow_mut().depr_map.insert(id, depr.clone());
-    depr
-}
-
-fn lookup_stability_uncached(self, id: DefId) -> Option<&'tcx Stability> {
-    debug!("lookup(id={:?})", id);
-    if id.is_local() {
-        None // The stability cache is filled partially lazily
-    } else {
-        self.sess.cstore.stability(id).map(|st| self.intern_stability(st))
+    fn lookup_stability_uncached(self, id: DefId) -> Option<&'tcx Stability> {
+        debug!("lookup(id={:?})", id);
+        if id.is_local() {
+            None // The stability cache is filled partially lazily
+        } else {
+            self.sess.cstore.stability(id).map(|st| self.intern_stability(st))
+        }
     }
-}
 
-fn lookup_deprecation_uncached(self, id: DefId) -> Option<Deprecation> {
-    debug!("lookup(id={:?})", id);
-    if id.is_local() {
-        None // The stability cache is filled partially lazily
-    } else {
-        self.sess.cstore.deprecation(id)
+    fn lookup_deprecation_uncached(self, id: DefId) -> Option<Deprecation> {
+        debug!("lookup(id={:?})", id);
+        if id.is_local() {
+            None // The stability cache is filled partially lazily
+        } else {
+            self.sess.cstore.deprecation(id)
+        }
     }
 }
-}
 
 /// Given the list of enabled features that were not language features (i.e. that
 /// were expected to be library features), and the list of features used from
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index bc573d956a7..6c037ebd2bc 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -61,840 +61,844 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-pub fn report_fulfillment_errors(&self, errors: &Vec<FulfillmentError<'tcx>>) {
-    for error in errors {
-        self.report_fulfillment_error(error, None);
-    }
-}
-
-pub fn report_fulfillment_errors_as_warnings(&self,
-                                             errors: &Vec<FulfillmentError<'tcx>>,
-                                             node_id: ast::NodeId) {
-    for error in errors {
-        self.report_fulfillment_error(error, Some(node_id));
-    }
-}
-
-fn report_fulfillment_error(&self,
-                            error: &FulfillmentError<'tcx>,
-                            warning_node_id: Option<ast::NodeId>) {
-    let error_key = TraitErrorKey::from_error(self, error, warning_node_id);
-    debug!("report_fulfillment_errors({:?}) - key={:?}",
-           error, error_key);
-    if !self.reported_trait_errors.borrow_mut().insert(error_key) {
-        debug!("report_fulfillment_errors: skipping duplicate");
-        return;
-    }
-    match error.code {
-        FulfillmentErrorCode::CodeSelectionError(ref e) => {
-            self.report_selection_error(&error.obligation, e, warning_node_id);
-        }
-        FulfillmentErrorCode::CodeProjectionError(ref e) => {
-            self.report_projection_error(&error.obligation, e, warning_node_id);
-        }
-        FulfillmentErrorCode::CodeAmbiguity => {
-            self.maybe_report_ambiguity(&error.obligation);
+    pub fn report_fulfillment_errors(&self, errors: &Vec<FulfillmentError<'tcx>>) {
+        for error in errors {
+            self.report_fulfillment_error(error, None);
         }
     }
-}
 
-fn report_projection_error(&self,
-                           obligation: &PredicateObligation<'tcx>,
-                           error: &MismatchedProjectionTypes<'tcx>,
-                           warning_node_id: Option<ast::NodeId>)
-{
-    let predicate =
-        self.resolve_type_vars_if_possible(&obligation.predicate);
-
-    if !predicate.references_error() {
-        if let Some(warning_node_id) = warning_node_id {
-            self.tcx.sess.add_lint(
-                ::lint::builtin::UNSIZED_IN_TUPLE,
-                warning_node_id,
-                obligation.cause.span,
-                format!("type mismatch resolving `{}`: {}",
-                        predicate,
-                        error.err));
-        } else {
-            let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271,
-                                           "type mismatch resolving `{}`: {}",
-                                           predicate,
-                                           error.err);
-            self.note_obligation_cause(&mut err, obligation);
-            err.emit();
+    pub fn report_fulfillment_errors_as_warnings(&self,
+                                                 errors: &Vec<FulfillmentError<'tcx>>,
+                                                 node_id: ast::NodeId) {
+        for error in errors {
+            self.report_fulfillment_error(error, Some(node_id));
         }
     }
-}
 
-fn on_unimplemented_note(&self,
-                         trait_ref: ty::PolyTraitRef<'tcx>,
-                         span: Span) -> Option<String> {
-    let trait_ref = trait_ref.skip_binder();
-    let def_id = trait_ref.def_id;
-    let mut report = None;
-    for item in self.tcx.get_attrs(def_id).iter() {
-        if item.check_name("rustc_on_unimplemented") {
-            let err_sp = item.meta().span.substitute_dummy(span);
-            let def = self.tcx.lookup_trait_def(def_id);
-            let trait_str = def.trait_ref.to_string();
-            if let Some(ref istring) = item.value_str() {
-                let mut generic_map = def.generics.types.iter_enumerated()
-                                         .map(|(param, i, gen)| {
-                                               (gen.name.as_str().to_string(),
-                                                trait_ref.substs.types.get(param, i)
-                                                         .to_string())
-                                              }).collect::<FnvHashMap<String, String>>();
-                generic_map.insert("Self".to_string(),
-                                   trait_ref.self_ty().to_string());
-                let parser = Parser::new(&istring);
-                let mut errored = false;
-                let err: String = parser.filter_map(|p| {
-                    match p {
-                        Piece::String(s) => Some(s),
-                        Piece::NextArgument(a) => match a.position {
-                            Position::ArgumentNamed(s) => match generic_map.get(s) {
-                                Some(val) => Some(val),
-                                None => {
-                                    span_err!(self.tcx.sess, err_sp, E0272,
-                                                   "the #[rustc_on_unimplemented] \
-                                                            attribute on \
-                                                            trait definition for {} refers to \
-                                                            non-existent type parameter {}",
-                                                           trait_str, s);
-                                    errored = true;
-                                    None
-                                }
-                            },
-                            _ => {
-                                     span_err!(self.tcx.sess, err_sp, E0273,
-                                               "the #[rustc_on_unimplemented] \
-                                                        attribute on \
-                                                        trait definition for {} must have named \
-                                                        format arguments, \
-                                                        eg `#[rustc_on_unimplemented = \
-                                                        \"foo {{T}}\"]`",
-                                                       trait_str);
-                                errored = true;
-                                None
-                            }
-                        }
-                    }
-                }).collect();
-                // Report only if the format string checks out
-                if !errored {
-                    report = Some(err);
-                }
+    fn report_fulfillment_error(&self,
+                                error: &FulfillmentError<'tcx>,
+                                warning_node_id: Option<ast::NodeId>) {
+        let error_key = TraitErrorKey::from_error(self, error, warning_node_id);
+        debug!("report_fulfillment_errors({:?}) - key={:?}",
+               error, error_key);
+        if !self.reported_trait_errors.borrow_mut().insert(error_key) {
+            debug!("report_fulfillment_errors: skipping duplicate");
+            return;
+        }
+        match error.code {
+            FulfillmentErrorCode::CodeSelectionError(ref e) => {
+                self.report_selection_error(&error.obligation, e, warning_node_id);
+            }
+            FulfillmentErrorCode::CodeProjectionError(ref e) => {
+                self.report_projection_error(&error.obligation, e, warning_node_id);
+            }
+            FulfillmentErrorCode::CodeAmbiguity => {
+                self.maybe_report_ambiguity(&error.obligation);
+            }
+        }
+    }
+
+    fn report_projection_error(&self,
+                               obligation: &PredicateObligation<'tcx>,
+                               error: &MismatchedProjectionTypes<'tcx>,
+                               warning_node_id: Option<ast::NodeId>)
+    {
+        let predicate =
+            self.resolve_type_vars_if_possible(&obligation.predicate);
+
+        if !predicate.references_error() {
+            if let Some(warning_node_id) = warning_node_id {
+                self.tcx.sess.add_lint(
+                    ::lint::builtin::UNSIZED_IN_TUPLE,
+                    warning_node_id,
+                    obligation.cause.span,
+                    format!("type mismatch resolving `{}`: {}",
+                            predicate,
+                            error.err));
             } else {
-                span_err!(self.tcx.sess, err_sp, E0274,
-                                        "the #[rustc_on_unimplemented] attribute on \
-                                                 trait definition for {} must have a value, \
-                                                 eg `#[rustc_on_unimplemented = \"foo\"]`",
-                                                 trait_str);
-            }
-            break;
-        }
-    }
-    report
-}
-
-fn report_similar_impl_candidates(&self,
-                                  trait_ref: ty::PolyTraitRef<'tcx>,
-                                  err: &mut DiagnosticBuilder)
-{
-    let simp = fast_reject::simplify_type(self.tcx,
-                                          trait_ref.skip_binder().self_ty(),
-                                          true);
-    let mut impl_candidates = Vec::new();
-    let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id());
-
-    match simp {
-        Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| {
-            let imp = self.tcx.impl_trait_ref(def_id).unwrap();
-            let imp_simp = fast_reject::simplify_type(self.tcx,
-                                                      imp.self_ty(),
-                                                      true);
-            if let Some(imp_simp) = imp_simp {
-                if simp != imp_simp {
-                    return;
-                }
-            }
-            impl_candidates.push(imp);
-        }),
-        None => trait_def.for_each_impl(self.tcx, |def_id| {
-            impl_candidates.push(
-                self.tcx.impl_trait_ref(def_id).unwrap());
-        })
-    };
-
-    if impl_candidates.is_empty() {
-        return;
-    }
-
-    err.help(&format!("the following implementations were found:"));
-
-    let end = cmp::min(4, impl_candidates.len());
-    for candidate in &impl_candidates[0..end] {
-        err.help(&format!("  {:?}", candidate));
-    }
-    if impl_candidates.len() > 4 {
-        err.help(&format!("and {} others", impl_candidates.len()-4));
-    }
-}
-
-/// Reports that an overflow has occurred and halts compilation. We
-/// halt compilation unconditionally because it is important that
-/// overflows never be masked -- they basically represent computations
-/// whose result could not be truly determined and thus we can't say
-/// if the program type checks or not -- and they are unusual
-/// occurrences in any case.
-pub fn report_overflow_error<T>(&self,
-                                obligation: &Obligation<'tcx, T>,
-                                suggest_increasing_limit: bool) -> !
-    where T: fmt::Display + TypeFoldable<'tcx>
-{
-    let predicate =
-        self.resolve_type_vars_if_possible(&obligation.predicate);
-    let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0275,
-                                   "overflow evaluating the requirement `{}`",
-                                   predicate);
-
-    if suggest_increasing_limit {
-        self.suggest_new_overflow_limit(&mut err);
-    }
-
-    self.note_obligation_cause(&mut err, obligation);
-
-    err.emit();
-    self.tcx.sess.abort_if_errors();
-    bug!();
-}
-
-/// Reports that a cycle was detected which led to overflow and halts
-/// compilation. This is equivalent to `report_overflow_error` except
-/// that we can give a more helpful error message (and, in particular,
-/// we do not suggest increasing the overflow limit, which is not
-/// going to help).
-pub fn report_overflow_error_cycle(&self, cycle: &Vec<PredicateObligation<'tcx>>) -> ! {
-    assert!(cycle.len() > 1);
-
-    debug!("report_overflow_error_cycle(cycle length = {})", cycle.len());
-
-    let cycle = self.resolve_type_vars_if_possible(cycle);
-
-    debug!("report_overflow_error_cycle: cycle={:?}", cycle);
-
-    assert_eq!(&cycle[0].predicate, &cycle.last().unwrap().predicate);
-
-    self.try_report_overflow_error_type_of_infinite_size(&cycle);
-    self.report_overflow_error(&cycle[0], false);
-}
-
-/// If a cycle results from evaluated whether something is Sized, that
-/// is a particular special case that always results from a struct or
-/// enum definition that lacks indirection (e.g., `struct Foo { x: Foo
-/// }`). We wish to report a targeted error for this case.
-pub fn try_report_overflow_error_type_of_infinite_size(&self,
-    cycle: &[PredicateObligation<'tcx>])
-{
-    let sized_trait = match self.tcx.lang_items.sized_trait() {
-        Some(v) => v,
-        None => return,
-    };
-    let top_is_sized = {
-        match cycle[0].predicate {
-            ty::Predicate::Trait(ref data) => data.def_id() == sized_trait,
-            _ => false,
-        }
-    };
-    if !top_is_sized {
-        return;
-    }
-
-    // The only way to have a type of infinite size is to have,
-    // somewhere, a struct/enum type involved. Identify all such types
-    // and report the cycle to the user.
-
-    let struct_enum_tys: Vec<_> =
-        cycle.iter()
-             .flat_map(|obligation| match obligation.predicate {
-                 ty::Predicate::Trait(ref data) => {
-                     assert_eq!(data.def_id(), sized_trait);
-                     let self_ty = data.skip_binder().trait_ref.self_ty(); // (*)
-                     // (*) ok to skip binder because this is just
-                     // error reporting and regions don't really
-                     // matter
-                     match self_ty.sty {
-                         ty::TyEnum(..) | ty::TyStruct(..) => Some(self_ty),
-                         _ => None,
-                     }
-                 }
-                 _ => {
-                     span_bug!(obligation.cause.span,
-                               "Sized cycle involving non-trait-ref: {:?}",
-                               obligation.predicate);
-                 }
-             })
-             .collect();
-
-    assert!(!struct_enum_tys.is_empty());
-
-    // This is a bit tricky. We want to pick a "main type" in the
-    // listing that is local to the current crate, so we can give a
-    // good span to the user. But it might not be the first one in our
-    // cycle list. So find the first one that is local and then
-    // rotate.
-    let (main_index, main_def_id) =
-        struct_enum_tys.iter()
-                       .enumerate()
-                       .filter_map(|(index, ty)| match ty.sty {
-                           ty::TyEnum(adt_def, _) | ty::TyStruct(adt_def, _)
-                               if adt_def.did.is_local() =>
-                               Some((index, adt_def.did)),
-                           _ =>
-                               None,
-                       })
-                       .next()
-                       .unwrap(); // should always be SOME local type involved!
-
-    // Rotate so that the "main" type is at index 0.
-    let struct_enum_tys: Vec<_> =
-        struct_enum_tys.iter()
-                       .cloned()
-                       .skip(main_index)
-                       .chain(struct_enum_tys.iter().cloned().take(main_index))
-                       .collect();
-
-    let tcx = self.tcx;
-    let mut err = tcx.recursive_type_with_infinite_size_error(main_def_id);
-    let len = struct_enum_tys.len();
-    if len > 2 {
-        err.note(&format!("type `{}` is embedded within `{}`...",
-                 struct_enum_tys[0],
-                 struct_enum_tys[1]));
-        for &next_ty in &struct_enum_tys[1..len-1] {
-            err.note(&format!("...which in turn is embedded within `{}`...", next_ty));
-        }
-        err.note(&format!("...which in turn is embedded within `{}`, \
-                           completing the cycle.",
-                          struct_enum_tys[len-1]));
-    }
-    err.emit();
-    self.tcx.sess.abort_if_errors();
-    bug!();
-}
-
-pub fn report_selection_error(&self,
-                              obligation: &PredicateObligation<'tcx>,
-                              error: &SelectionError<'tcx>,
-                              warning_node_id: Option<ast::NodeId>)
-{
-    let span = obligation.cause.span;
-    let mut err = match *error {
-        SelectionError::Unimplemented => {
-            if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code {
-                span_err!(
-                    self.tcx.sess, span, E0276,
-                    "the requirement `{}` appears on the impl \
-                     method but not on the corresponding trait method",
-                    obligation.predicate);
-                return;
-            } else {
-                match obligation.predicate {
-                    ty::Predicate::Trait(ref trait_predicate) => {
-                        let trait_predicate =
-                            self.resolve_type_vars_if_possible(trait_predicate);
-
-                        if self.tcx.sess.has_errors() && trait_predicate.references_error() {
-                            return;
-                        } else {
-                            let trait_ref = trait_predicate.to_poly_trait_ref();
-
-                            if let Some(warning_node_id) = warning_node_id {
-                                self.tcx.sess.add_lint(
-                                    ::lint::builtin::UNSIZED_IN_TUPLE,
-                                    warning_node_id,
-                                    obligation.cause.span,
-                                    format!("the trait bound `{}` is not satisfied",
-                                            trait_ref.to_predicate()));
-                                return;
-                            }
-
-                            let mut err = struct_span_err!(
-                                self.tcx.sess, span, E0277,
-                                "the trait bound `{}` is not satisfied",
-                                trait_ref.to_predicate());
-
-                            // Try to report a help message
-
-                            if !trait_ref.has_infer_types() &&
-                                self.predicate_can_apply(trait_ref)
-                            {
-                                // If a where-clause may be useful, remind the
-                                // user that they can add it.
-                                //
-                                // don't display an on-unimplemented note, as
-                                // these notes will often be of the form
-                                //     "the type `T` can't be frobnicated"
-                                // which is somewhat confusing.
-                                err.help(&format!("consider adding a `where {}` bound",
-                                    trait_ref.to_predicate()
-                                    ));
-                            } else if let Some(s) = self.on_unimplemented_note(trait_ref, span) {
-                                // Otherwise, if there is an on-unimplemented note,
-                                // display it.
-                                err.note(&s);
-                            } else {
-                                // If we can't show anything useful, try to find
-                                // similar impls.
-
-                                self.report_similar_impl_candidates(trait_ref, &mut err);
-                            }
-                            err
-                        }
-                    },
-                    ty::Predicate::Equate(ref predicate) => {
-                        let predicate = self.resolve_type_vars_if_possible(predicate);
-                        let err = self.equality_predicate(span,
-                                                          &predicate).err().unwrap();
-                        struct_span_err!(self.tcx.sess, span, E0278,
-                            "the requirement `{}` is not satisfied (`{}`)",
-                            predicate, err)
-                    }
-
-                    ty::Predicate::RegionOutlives(ref predicate) => {
-                        let predicate = self.resolve_type_vars_if_possible(predicate);
-                        let err = self.region_outlives_predicate(span,
-                                                                 &predicate).err().unwrap();
-                        struct_span_err!(self.tcx.sess, span, E0279,
-                            "the requirement `{}` is not satisfied (`{}`)",
-                            predicate, err)
-                    }
-
-                    ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
-                        let predicate =
-                            self.resolve_type_vars_if_possible(&obligation.predicate);
-                        struct_span_err!(self.tcx.sess, span, E0280,
-                            "the requirement `{}` is not satisfied",
-                            predicate)
-                    }
-
-                    ty::Predicate::ObjectSafe(trait_def_id) => {
-                        let violations = self.tcx.object_safety_violations(trait_def_id);
-                        let err = self.tcx.report_object_safety_error(span,
-                                                                      trait_def_id,
-                                                                      warning_node_id,
-                                                                      violations);
-                        if let Some(err) = err {
-                            err
-                        } else {
-                            return;
-                        }
-                    }
-
-                    ty::Predicate::ClosureKind(closure_def_id, kind) => {
-                        let found_kind = self.closure_kind(closure_def_id).unwrap();
-                        let closure_span = self.tcx.map.span_if_local(closure_def_id).unwrap();
-                        let mut err = struct_span_err!(
-                            self.tcx.sess, closure_span, E0525,
-                            "expected a closure that implements the `{}` trait, but this closure \
-                             only implements `{}`",
-                            kind,
-                            found_kind);
-                        err.span_note(
-                            obligation.cause.span,
-                            &format!("the requirement to implement `{}` derives from here", kind));
-                        err.emit();
-                        return;
-                    }
-
-                    ty::Predicate::WellFormed(ty) => {
-                        // WF predicates cannot themselves make
-                        // errors. They can only block due to
-                        // ambiguity; otherwise, they always
-                        // degenerate into other obligations
-                        // (which may fail).
-                        span_bug!(span, "WF predicate not satisfied for {:?}", ty);
-                    }
-
-                    ty::Predicate::Rfc1592(ref data) => {
-                        span_bug!(
-                            obligation.cause.span,
-                            "RFC1592 predicate not satisfied for {:?}",
-                            data);
-                    }
-                }
-            }
-        }
-
-        OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
-            let expected_trait_ref = self.resolve_type_vars_if_possible(&*expected_trait_ref);
-            let actual_trait_ref = self.resolve_type_vars_if_possible(&*actual_trait_ref);
-            if actual_trait_ref.self_ty().references_error() {
-                return;
-            }
-            struct_span_err!(self.tcx.sess, span, E0281,
-                "type mismatch: the type `{}` implements the trait `{}`, \
-                 but the trait `{}` is required ({})",
-                expected_trait_ref.self_ty(),
-                expected_trait_ref,
-                actual_trait_ref,
-                e)
-        }
-
-        TraitNotObjectSafe(did) => {
-            let violations = self.tcx.object_safety_violations(did);
-            let err = self.tcx.report_object_safety_error(span, did,
-                                                          warning_node_id,
-                                                          violations);
-            if let Some(err) = err {
-                err
-            } else {
-                return;
-            }
-        }
-    };
-    self.note_obligation_cause(&mut err, obligation);
-    err.emit();
-}
-}
-
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-pub fn recursive_type_with_infinite_size_error(self,
-                                               type_def_id: DefId)
-                                               -> DiagnosticBuilder<'tcx>
-{
-    assert!(type_def_id.is_local());
-    let span = self.map.span_if_local(type_def_id).unwrap();
-    let mut err = struct_span_err!(self.sess, span, E0072, "recursive type `{}` has infinite size",
-                                   self.item_path_str(type_def_id));
-    err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
-                       at some point to make `{}` representable",
-                      self.item_path_str(type_def_id)));
-    err
-}
-
-pub fn report_object_safety_error(self,
-                                  span: Span,
-                                  trait_def_id: DefId,
-                                  warning_node_id: Option<ast::NodeId>,
-                                  violations: Vec<ObjectSafetyViolation>)
-                                  -> Option<DiagnosticBuilder<'tcx>>
-{
-    let mut err = match warning_node_id {
-        Some(_) => None,
-        None => {
-            Some(struct_span_err!(
-                self.sess, span, E0038,
-                "the trait `{}` cannot be made into an object",
-                self.item_path_str(trait_def_id)))
-        }
-    };
-
-    let mut reported_violations = FnvHashSet();
-    for violation in violations {
-        if !reported_violations.insert(violation.clone()) {
-            continue;
-        }
-        let buf;
-        let note = match violation {
-            ObjectSafetyViolation::SizedSelf => {
-                "the trait cannot require that `Self : Sized`"
-            }
-
-            ObjectSafetyViolation::SupertraitSelf => {
-                "the trait cannot use `Self` as a type parameter \
-                     in the supertrait listing"
-            }
-
-            ObjectSafetyViolation::Method(method,
-                                          MethodViolationCode::StaticMethod) => {
-                buf = format!("method `{}` has no receiver",
-                              method.name);
-                &buf
-            }
-
-            ObjectSafetyViolation::Method(method,
-                                          MethodViolationCode::ReferencesSelf) => {
-                buf = format!("method `{}` references the `Self` type \
-                                   in its arguments or return type",
-                              method.name);
-                &buf
-            }
-
-            ObjectSafetyViolation::Method(method,
-                                          MethodViolationCode::Generic) => {
-                buf = format!("method `{}` has generic type parameters",
-                              method.name);
-                &buf
-            }
-        };
-        match (warning_node_id, &mut err) {
-            (Some(node_id), &mut None) => {
-                self.sess.add_lint(
-                    ::lint::builtin::OBJECT_UNSAFE_FRAGMENT,
-                    node_id,
-                    span,
-                    note.to_string());
-            }
-            (None, &mut Some(ref mut err)) => {
-                err.note(note);
-            }
-            _ => unreachable!()
-        }
-    }
-    err
-}
-}
-
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
-    // Unable to successfully determine, probably means
-    // insufficient type information, but could mean
-    // ambiguous impls. The latter *ought* to be a
-    // coherence violation, so we don't report it here.
-
-    let predicate = self.resolve_type_vars_if_possible(&obligation.predicate);
-
-    debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})",
-           predicate,
-           obligation);
-
-    // Ambiguity errors are often caused as fallout from earlier
-    // errors. So just ignore them if this infcx is tainted.
-    if self.is_tainted_by_errors() {
-        return;
-    }
-
-    match predicate {
-        ty::Predicate::Trait(ref data) => {
-            let trait_ref = data.to_poly_trait_ref();
-            let self_ty = trait_ref.self_ty();
-            let all_types = &trait_ref.substs().types;
-            if all_types.references_error() {
-            } else {
-                // Typically, this ambiguity should only happen if
-                // there are unresolved type inference variables
-                // (otherwise it would suggest a coherence
-                // failure). But given #21974 that is not necessarily
-                // the case -- we can have multiple where clauses that
-                // are only distinguished by a region, which results
-                // in an ambiguity even when all types are fully
-                // known, since we don't dispatch based on region
-                // relationships.
-
-                // This is kind of a hack: it frequently happens that some earlier
-                // error prevents types from being fully inferred, and then we get
-                // a bunch of uninteresting errors saying something like "<generic
-                // #0> doesn't implement Sized".  It may even be true that we
-                // could just skip over all checks where the self-ty is an
-                // inference variable, but I was afraid that there might be an
-                // inference variable created, registered as an obligation, and
-                // then never forced by writeback, and hence by skipping here we'd
-                // be ignoring the fact that we don't KNOW the type works
-                // out. Though even that would probably be harmless, given that
-                // we're only talking about builtin traits, which are known to be
-                // inhabited. But in any case I just threw in this check for
-                // has_errors() to be sure that compilation isn't happening
-                // anyway. In that case, why inundate the user.
-                if !self.tcx.sess.has_errors() {
-                    if
-                        self.tcx.lang_items.sized_trait()
-                        .map_or(false, |sized_id| sized_id == trait_ref.def_id())
-                    {
-                        self.need_type_info(obligation.cause.span, self_ty);
-                    } else {
-                        let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0283,
-                                                       "type annotations required: \
-                                                        cannot resolve `{}`",
-                                                       predicate);
-                        self.note_obligation_cause(&mut err, obligation);
-                        err.emit();
-                    }
-                }
-            }
-        }
-
-        ty::Predicate::WellFormed(ty) => {
-            // Same hacky approach as above to avoid deluging user
-            // with error messages.
-            if !ty.references_error() && !self.tcx.sess.has_errors() {
-                self.need_type_info(obligation.cause.span, ty);
-            }
-        }
-
-        _ => {
-            if !self.tcx.sess.has_errors() {
-                let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0284,
-                                               "type annotations required: cannot resolve `{}`",
-                                               predicate);
+                let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271,
+                                               "type mismatch resolving `{}`: {}",
+                                               predicate,
+                                               error.err);
                 self.note_obligation_cause(&mut err, obligation);
                 err.emit();
             }
         }
     }
-}
 
-/// Returns whether the trait predicate may apply for *some* assignment
-/// to the type parameters.
-fn predicate_can_apply(&self, pred: ty::PolyTraitRef<'tcx>) -> bool {
-    struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-        infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-        var_map: FnvHashMap<Ty<'tcx>, Ty<'tcx>>
+    fn on_unimplemented_note(&self,
+                             trait_ref: ty::PolyTraitRef<'tcx>,
+                             span: Span) -> Option<String> {
+        let trait_ref = trait_ref.skip_binder();
+        let def_id = trait_ref.def_id;
+        let mut report = None;
+        for item in self.tcx.get_attrs(def_id).iter() {
+            if item.check_name("rustc_on_unimplemented") {
+                let err_sp = item.meta().span.substitute_dummy(span);
+                let def = self.tcx.lookup_trait_def(def_id);
+                let trait_str = def.trait_ref.to_string();
+                if let Some(ref istring) = item.value_str() {
+                    let mut generic_map = def.generics.types.iter_enumerated()
+                                             .map(|(param, i, gen)| {
+                                                   (gen.name.as_str().to_string(),
+                                                    trait_ref.substs.types.get(param, i)
+                                                             .to_string())
+                                                  }).collect::<FnvHashMap<String, String>>();
+                    generic_map.insert("Self".to_string(),
+                                       trait_ref.self_ty().to_string());
+                    let parser = Parser::new(&istring);
+                    let mut errored = false;
+                    let err: String = parser.filter_map(|p| {
+                        match p {
+                            Piece::String(s) => Some(s),
+                            Piece::NextArgument(a) => match a.position {
+                                Position::ArgumentNamed(s) => match generic_map.get(s) {
+                                    Some(val) => Some(val),
+                                    None => {
+                                        span_err!(self.tcx.sess, err_sp, E0272,
+                                                       "the #[rustc_on_unimplemented] \
+                                                                attribute on \
+                                                                trait definition for {} refers to \
+                                                                non-existent type parameter {}",
+                                                               trait_str, s);
+                                        errored = true;
+                                        None
+                                    }
+                                },
+                                _ => {
+                                    span_err!(self.tcx.sess, err_sp, E0273,
+                                              "the #[rustc_on_unimplemented] attribute \
+                                               on trait definition for {} must have \
+                                               named format arguments, eg \
+                                               `#[rustc_on_unimplemented = \
+                                                \"foo {{T}}\"]`", trait_str);
+                                    errored = true;
+                                    None
+                                }
+                            }
+                        }
+                    }).collect();
+                    // Report only if the format string checks out
+                    if !errored {
+                        report = Some(err);
+                    }
+                } else {
+                    span_err!(self.tcx.sess, err_sp, E0274,
+                                            "the #[rustc_on_unimplemented] attribute on \
+                                                     trait definition for {} must have a value, \
+                                                     eg `#[rustc_on_unimplemented = \"foo\"]`",
+                                                     trait_str);
+                }
+                break;
+            }
+        }
+        report
     }
 
-    impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ParamToVarFolder<'a, 'gcx, 'tcx> {
-        fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.infcx.tcx }
+    fn report_similar_impl_candidates(&self,
+                                      trait_ref: ty::PolyTraitRef<'tcx>,
+                                      err: &mut DiagnosticBuilder)
+    {
+        let simp = fast_reject::simplify_type(self.tcx,
+                                              trait_ref.skip_binder().self_ty(),
+                                              true);
+        let mut impl_candidates = Vec::new();
+        let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id());
 
-        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-            if let ty::TyParam(..) = ty.sty {
-                let infcx = self.infcx;
-                self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var())
-            } else {
-                ty.super_fold_with(self)
+        match simp {
+            Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| {
+                let imp = self.tcx.impl_trait_ref(def_id).unwrap();
+                let imp_simp = fast_reject::simplify_type(self.tcx,
+                                                          imp.self_ty(),
+                                                          true);
+                if let Some(imp_simp) = imp_simp {
+                    if simp != imp_simp {
+                        return;
+                    }
+                }
+                impl_candidates.push(imp);
+            }),
+            None => trait_def.for_each_impl(self.tcx, |def_id| {
+                impl_candidates.push(
+                    self.tcx.impl_trait_ref(def_id).unwrap());
+            })
+        };
+
+        if impl_candidates.is_empty() {
+            return;
+        }
+
+        err.help(&format!("the following implementations were found:"));
+
+        let end = cmp::min(4, impl_candidates.len());
+        for candidate in &impl_candidates[0..end] {
+            err.help(&format!("  {:?}", candidate));
+        }
+        if impl_candidates.len() > 4 {
+            err.help(&format!("and {} others", impl_candidates.len()-4));
+        }
+    }
+
+    /// Reports that an overflow has occurred and halts compilation. We
+    /// halt compilation unconditionally because it is important that
+    /// overflows never be masked -- they basically represent computations
+    /// whose result could not be truly determined and thus we can't say
+    /// if the program type checks or not -- and they are unusual
+    /// occurrences in any case.
+    pub fn report_overflow_error<T>(&self,
+                                    obligation: &Obligation<'tcx, T>,
+                                    suggest_increasing_limit: bool) -> !
+        where T: fmt::Display + TypeFoldable<'tcx>
+    {
+        let predicate =
+            self.resolve_type_vars_if_possible(&obligation.predicate);
+        let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0275,
+                                       "overflow evaluating the requirement `{}`",
+                                       predicate);
+
+        if suggest_increasing_limit {
+            self.suggest_new_overflow_limit(&mut err);
+        }
+
+        self.note_obligation_cause(&mut err, obligation);
+
+        err.emit();
+        self.tcx.sess.abort_if_errors();
+        bug!();
+    }
+
+    /// Reports that a cycle was detected which led to overflow and halts
+    /// compilation. This is equivalent to `report_overflow_error` except
+    /// that we can give a more helpful error message (and, in particular,
+    /// we do not suggest increasing the overflow limit, which is not
+    /// going to help).
+    pub fn report_overflow_error_cycle(&self, cycle: &Vec<PredicateObligation<'tcx>>) -> ! {
+        assert!(cycle.len() > 1);
+
+        debug!("report_overflow_error_cycle(cycle length = {})", cycle.len());
+
+        let cycle = self.resolve_type_vars_if_possible(cycle);
+
+        debug!("report_overflow_error_cycle: cycle={:?}", cycle);
+
+        assert_eq!(&cycle[0].predicate, &cycle.last().unwrap().predicate);
+
+        self.try_report_overflow_error_type_of_infinite_size(&cycle);
+        self.report_overflow_error(&cycle[0], false);
+    }
+
+    /// If a cycle results from evaluated whether something is Sized, that
+    /// is a particular special case that always results from a struct or
+    /// enum definition that lacks indirection (e.g., `struct Foo { x: Foo
+    /// }`). We wish to report a targeted error for this case.
+    pub fn try_report_overflow_error_type_of_infinite_size(&self,
+        cycle: &[PredicateObligation<'tcx>])
+    {
+        let sized_trait = match self.tcx.lang_items.sized_trait() {
+            Some(v) => v,
+            None => return,
+        };
+        let top_is_sized = {
+            match cycle[0].predicate {
+                ty::Predicate::Trait(ref data) => data.def_id() == sized_trait,
+                _ => false,
+            }
+        };
+        if !top_is_sized {
+            return;
+        }
+
+        // The only way to have a type of infinite size is to have,
+        // somewhere, a struct/enum type involved. Identify all such types
+        // and report the cycle to the user.
+
+        let struct_enum_tys: Vec<_> =
+            cycle.iter()
+                 .flat_map(|obligation| match obligation.predicate {
+                     ty::Predicate::Trait(ref data) => {
+                         assert_eq!(data.def_id(), sized_trait);
+                         let self_ty = data.skip_binder().trait_ref.self_ty(); // (*)
+                         // (*) ok to skip binder because this is just
+                         // error reporting and regions don't really
+                         // matter
+                         match self_ty.sty {
+                             ty::TyEnum(..) | ty::TyStruct(..) => Some(self_ty),
+                             _ => None,
+                         }
+                     }
+                     _ => {
+                         span_bug!(obligation.cause.span,
+                                   "Sized cycle involving non-trait-ref: {:?}",
+                                   obligation.predicate);
+                     }
+                 })
+                 .collect();
+
+        assert!(!struct_enum_tys.is_empty());
+
+        // This is a bit tricky. We want to pick a "main type" in the
+        // listing that is local to the current crate, so we can give a
+        // good span to the user. But it might not be the first one in our
+        // cycle list. So find the first one that is local and then
+        // rotate.
+        let (main_index, main_def_id) =
+            struct_enum_tys.iter()
+                           .enumerate()
+                           .filter_map(|(index, ty)| match ty.sty {
+                               ty::TyEnum(adt_def, _) | ty::TyStruct(adt_def, _)
+                                   if adt_def.did.is_local() =>
+                                   Some((index, adt_def.did)),
+                               _ =>
+                                   None,
+                           })
+                           .next()
+                           .unwrap(); // should always be SOME local type involved!
+
+        // Rotate so that the "main" type is at index 0.
+        let struct_enum_tys: Vec<_> =
+            struct_enum_tys.iter()
+                           .cloned()
+                           .skip(main_index)
+                           .chain(struct_enum_tys.iter().cloned().take(main_index))
+                           .collect();
+
+        let tcx = self.tcx;
+        let mut err = tcx.recursive_type_with_infinite_size_error(main_def_id);
+        let len = struct_enum_tys.len();
+        if len > 2 {
+            err.note(&format!("type `{}` is embedded within `{}`...",
+                     struct_enum_tys[0],
+                     struct_enum_tys[1]));
+            for &next_ty in &struct_enum_tys[1..len-1] {
+                err.note(&format!("...which in turn is embedded within `{}`...", next_ty));
+            }
+            err.note(&format!("...which in turn is embedded within `{}`, \
+                               completing the cycle.",
+                              struct_enum_tys[len-1]));
+        }
+        err.emit();
+        self.tcx.sess.abort_if_errors();
+        bug!();
+    }
+
+    pub fn report_selection_error(&self,
+                                  obligation: &PredicateObligation<'tcx>,
+                                  error: &SelectionError<'tcx>,
+                                  warning_node_id: Option<ast::NodeId>)
+    {
+        let span = obligation.cause.span;
+        let mut err = match *error {
+            SelectionError::Unimplemented => {
+                if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code {
+                    span_err!(
+                        self.tcx.sess, span, E0276,
+                        "the requirement `{}` appears on the impl \
+                         method but not on the corresponding trait method",
+                        obligation.predicate);
+                    return;
+                } else {
+                    match obligation.predicate {
+                        ty::Predicate::Trait(ref trait_predicate) => {
+                            let trait_predicate =
+                                self.resolve_type_vars_if_possible(trait_predicate);
+
+                            if self.tcx.sess.has_errors() && trait_predicate.references_error() {
+                                return;
+                            } else {
+                                let trait_ref = trait_predicate.to_poly_trait_ref();
+
+                                if let Some(warning_node_id) = warning_node_id {
+                                    self.tcx.sess.add_lint(
+                                        ::lint::builtin::UNSIZED_IN_TUPLE,
+                                        warning_node_id,
+                                        obligation.cause.span,
+                                        format!("the trait bound `{}` is not satisfied",
+                                                trait_ref.to_predicate()));
+                                    return;
+                                }
+
+                                let mut err = struct_span_err!(
+                                    self.tcx.sess, span, E0277,
+                                    "the trait bound `{}` is not satisfied",
+                                    trait_ref.to_predicate());
+
+                                // Try to report a help message
+
+                                if !trait_ref.has_infer_types() &&
+                                    self.predicate_can_apply(trait_ref)
+                                {
+                                    // If a where-clause may be useful, remind the
+                                    // user that they can add it.
+                                    //
+                                    // don't display an on-unimplemented note, as
+                                    // these notes will often be of the form
+                                    //     "the type `T` can't be frobnicated"
+                                    // which is somewhat confusing.
+                                    err.help(&format!("consider adding a `where {}` bound",
+                                        trait_ref.to_predicate()
+                                        ));
+                                } else if let Some(s) =
+                                        self.on_unimplemented_note(trait_ref, span) {
+                                    // Otherwise, if there is an on-unimplemented note,
+                                    // display it.
+                                    err.note(&s);
+                                } else {
+                                    // If we can't show anything useful, try to find
+                                    // similar impls.
+
+                                    self.report_similar_impl_candidates(trait_ref, &mut err);
+                                }
+                                err
+                            }
+                        },
+                        ty::Predicate::Equate(ref predicate) => {
+                            let predicate = self.resolve_type_vars_if_possible(predicate);
+                            let err = self.equality_predicate(span,
+                                                              &predicate).err().unwrap();
+                            struct_span_err!(self.tcx.sess, span, E0278,
+                                "the requirement `{}` is not satisfied (`{}`)",
+                                predicate, err)
+                        }
+
+                        ty::Predicate::RegionOutlives(ref predicate) => {
+                            let predicate = self.resolve_type_vars_if_possible(predicate);
+                            let err = self.region_outlives_predicate(span,
+                                                                     &predicate).err().unwrap();
+                            struct_span_err!(self.tcx.sess, span, E0279,
+                                "the requirement `{}` is not satisfied (`{}`)",
+                                predicate, err)
+                        }
+
+                        ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
+                            let predicate =
+                                self.resolve_type_vars_if_possible(&obligation.predicate);
+                            struct_span_err!(self.tcx.sess, span, E0280,
+                                "the requirement `{}` is not satisfied",
+                                predicate)
+                        }
+
+                        ty::Predicate::ObjectSafe(trait_def_id) => {
+                            let violations = self.tcx.object_safety_violations(trait_def_id);
+                            let err = self.tcx.report_object_safety_error(span,
+                                                                          trait_def_id,
+                                                                          warning_node_id,
+                                                                          violations);
+                            if let Some(err) = err {
+                                err
+                            } else {
+                                return;
+                            }
+                        }
+
+                        ty::Predicate::ClosureKind(closure_def_id, kind) => {
+                            let found_kind = self.closure_kind(closure_def_id).unwrap();
+                            let closure_span = self.tcx.map.span_if_local(closure_def_id).unwrap();
+                            let mut err = struct_span_err!(
+                                self.tcx.sess, closure_span, E0525,
+                                "expected a closure that implements the `{}` trait, \
+                                 but this closure only implements `{}`",
+                                kind,
+                                found_kind);
+                            err.span_note(
+                                obligation.cause.span,
+                                &format!("the requirement to implement \
+                                          `{}` derives from here", kind));
+                            err.emit();
+                            return;
+                        }
+
+                        ty::Predicate::WellFormed(ty) => {
+                            // WF predicates cannot themselves make
+                            // errors. They can only block due to
+                            // ambiguity; otherwise, they always
+                            // degenerate into other obligations
+                            // (which may fail).
+                            span_bug!(span, "WF predicate not satisfied for {:?}", ty);
+                        }
+
+                        ty::Predicate::Rfc1592(ref data) => {
+                            span_bug!(
+                                obligation.cause.span,
+                                "RFC1592 predicate not satisfied for {:?}",
+                                data);
+                        }
+                    }
+                }
+            }
+
+            OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
+                let expected_trait_ref = self.resolve_type_vars_if_possible(&*expected_trait_ref);
+                let actual_trait_ref = self.resolve_type_vars_if_possible(&*actual_trait_ref);
+                if actual_trait_ref.self_ty().references_error() {
+                    return;
+                }
+                struct_span_err!(self.tcx.sess, span, E0281,
+                    "type mismatch: the type `{}` implements the trait `{}`, \
+                     but the trait `{}` is required ({})",
+                    expected_trait_ref.self_ty(),
+                    expected_trait_ref,
+                    actual_trait_ref,
+                    e)
+            }
+
+            TraitNotObjectSafe(did) => {
+                let violations = self.tcx.object_safety_violations(did);
+                let err = self.tcx.report_object_safety_error(span, did,
+                                                              warning_node_id,
+                                                              violations);
+                if let Some(err) = err {
+                    err
+                } else {
+                    return;
+                }
+            }
+        };
+        self.note_obligation_cause(&mut err, obligation);
+        err.emit();
+    }
+}
+
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+    pub fn recursive_type_with_infinite_size_error(self,
+                                                   type_def_id: DefId)
+                                                   -> DiagnosticBuilder<'tcx>
+    {
+        assert!(type_def_id.is_local());
+        let span = self.map.span_if_local(type_def_id).unwrap();
+        let mut err = struct_span_err!(self.sess, span, E0072,
+                                       "recursive type `{}` has infinite size",
+                                       self.item_path_str(type_def_id));
+        err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
+                           at some point to make `{}` representable",
+                          self.item_path_str(type_def_id)));
+        err
+    }
+
+    pub fn report_object_safety_error(self,
+                                      span: Span,
+                                      trait_def_id: DefId,
+                                      warning_node_id: Option<ast::NodeId>,
+                                      violations: Vec<ObjectSafetyViolation>)
+                                      -> Option<DiagnosticBuilder<'tcx>>
+    {
+        let mut err = match warning_node_id {
+            Some(_) => None,
+            None => {
+                Some(struct_span_err!(
+                    self.sess, span, E0038,
+                    "the trait `{}` cannot be made into an object",
+                    self.item_path_str(trait_def_id)))
+            }
+        };
+
+        let mut reported_violations = FnvHashSet();
+        for violation in violations {
+            if !reported_violations.insert(violation.clone()) {
+                continue;
+            }
+            let buf;
+            let note = match violation {
+                ObjectSafetyViolation::SizedSelf => {
+                    "the trait cannot require that `Self : Sized`"
+                }
+
+                ObjectSafetyViolation::SupertraitSelf => {
+                    "the trait cannot use `Self` as a type parameter \
+                         in the supertrait listing"
+                }
+
+                ObjectSafetyViolation::Method(method,
+                                              MethodViolationCode::StaticMethod) => {
+                    buf = format!("method `{}` has no receiver",
+                                  method.name);
+                    &buf
+                }
+
+                ObjectSafetyViolation::Method(method,
+                                              MethodViolationCode::ReferencesSelf) => {
+                    buf = format!("method `{}` references the `Self` type \
+                                       in its arguments or return type",
+                                  method.name);
+                    &buf
+                }
+
+                ObjectSafetyViolation::Method(method,
+                                              MethodViolationCode::Generic) => {
+                    buf = format!("method `{}` has generic type parameters",
+                                  method.name);
+                    &buf
+                }
+            };
+            match (warning_node_id, &mut err) {
+                (Some(node_id), &mut None) => {
+                    self.sess.add_lint(
+                        ::lint::builtin::OBJECT_UNSAFE_FRAGMENT,
+                        node_id,
+                        span,
+                        note.to_string());
+                }
+                (None, &mut Some(ref mut err)) => {
+                    err.note(note);
+                }
+                _ => unreachable!()
+            }
+        }
+        err
+    }
+}
+
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+    fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
+        // Unable to successfully determine, probably means
+        // insufficient type information, but could mean
+        // ambiguous impls. The latter *ought* to be a
+        // coherence violation, so we don't report it here.
+
+        let predicate = self.resolve_type_vars_if_possible(&obligation.predicate);
+
+        debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})",
+               predicate,
+               obligation);
+
+        // Ambiguity errors are often caused as fallout from earlier
+        // errors. So just ignore them if this infcx is tainted.
+        if self.is_tainted_by_errors() {
+            return;
+        }
+
+        match predicate {
+            ty::Predicate::Trait(ref data) => {
+                let trait_ref = data.to_poly_trait_ref();
+                let self_ty = trait_ref.self_ty();
+                let all_types = &trait_ref.substs().types;
+                if all_types.references_error() {
+                } else {
+                    // Typically, this ambiguity should only happen if
+                    // there are unresolved type inference variables
+                    // (otherwise it would suggest a coherence
+                    // failure). But given #21974 that is not necessarily
+                    // the case -- we can have multiple where clauses that
+                    // are only distinguished by a region, which results
+                    // in an ambiguity even when all types are fully
+                    // known, since we don't dispatch based on region
+                    // relationships.
+
+                    // This is kind of a hack: it frequently happens that some earlier
+                    // error prevents types from being fully inferred, and then we get
+                    // a bunch of uninteresting errors saying something like "<generic
+                    // #0> doesn't implement Sized".  It may even be true that we
+                    // could just skip over all checks where the self-ty is an
+                    // inference variable, but I was afraid that there might be an
+                    // inference variable created, registered as an obligation, and
+                    // then never forced by writeback, and hence by skipping here we'd
+                    // be ignoring the fact that we don't KNOW the type works
+                    // out. Though even that would probably be harmless, given that
+                    // we're only talking about builtin traits, which are known to be
+                    // inhabited. But in any case I just threw in this check for
+                    // has_errors() to be sure that compilation isn't happening
+                    // anyway. In that case, why inundate the user.
+                    if !self.tcx.sess.has_errors() {
+                        if
+                            self.tcx.lang_items.sized_trait()
+                            .map_or(false, |sized_id| sized_id == trait_ref.def_id())
+                        {
+                            self.need_type_info(obligation.cause.span, self_ty);
+                        } else {
+                            let mut err = struct_span_err!(self.tcx.sess,
+                                                           obligation.cause.span, E0283,
+                                                           "type annotations required: \
+                                                            cannot resolve `{}`",
+                                                           predicate);
+                            self.note_obligation_cause(&mut err, obligation);
+                            err.emit();
+                        }
+                    }
+                }
+            }
+
+            ty::Predicate::WellFormed(ty) => {
+                // Same hacky approach as above to avoid deluging user
+                // with error messages.
+                if !ty.references_error() && !self.tcx.sess.has_errors() {
+                    self.need_type_info(obligation.cause.span, ty);
+                }
+            }
+
+            _ => {
+                if !self.tcx.sess.has_errors() {
+                    let mut err = struct_span_err!(self.tcx.sess,
+                                                   obligation.cause.span, E0284,
+                                                   "type annotations required: \
+                                                    cannot resolve `{}`",
+                                                   predicate);
+                    self.note_obligation_cause(&mut err, obligation);
+                    err.emit();
+                }
             }
         }
     }
 
-    self.probe(|_| {
-        let mut selcx = SelectionContext::new(self);
+    /// Returns whether the trait predicate may apply for *some* assignment
+    /// to the type parameters.
+    fn predicate_can_apply(&self, pred: ty::PolyTraitRef<'tcx>) -> bool {
+        struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+            infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+            var_map: FnvHashMap<Ty<'tcx>, Ty<'tcx>>
+        }
 
-        let cleaned_pred = pred.fold_with(&mut ParamToVarFolder {
-            infcx: self,
-            var_map: FnvHashMap()
-        });
+        impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ParamToVarFolder<'a, 'gcx, 'tcx> {
+            fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.infcx.tcx }
 
-        let cleaned_pred = super::project::normalize(
-            &mut selcx,
-            ObligationCause::dummy(),
-            &cleaned_pred
-        ).value;
+            fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+                if let ty::TyParam(..) = ty.sty {
+                    let infcx = self.infcx;
+                    self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var())
+                } else {
+                    ty.super_fold_with(self)
+                }
+            }
+        }
 
-        let obligation = Obligation::new(
-            ObligationCause::dummy(),
-            cleaned_pred.to_predicate()
-        );
+        self.probe(|_| {
+            let mut selcx = SelectionContext::new(self);
 
-        selcx.evaluate_obligation(&obligation)
-    })
-}
+            let cleaned_pred = pred.fold_with(&mut ParamToVarFolder {
+                infcx: self,
+                var_map: FnvHashMap()
+            });
+
+            let cleaned_pred = super::project::normalize(
+                &mut selcx,
+                ObligationCause::dummy(),
+                &cleaned_pred
+            ).value;
+
+            let obligation = Obligation::new(
+                ObligationCause::dummy(),
+                cleaned_pred.to_predicate()
+            );
+
+            selcx.evaluate_obligation(&obligation)
+        })
+    }
 
 
-fn need_type_info(&self, span: Span, ty: Ty<'tcx>) {
-    span_err!(self.tcx.sess, span, E0282,
-              "unable to infer enough type information about `{}`; \
-               type annotations or generic parameter binding required",
-              ty);
-}
+    fn need_type_info(&self, span: Span, ty: Ty<'tcx>) {
+        span_err!(self.tcx.sess, span, E0282,
+                  "unable to infer enough type information about `{}`; \
+                   type annotations or generic parameter binding required",
+                  ty);
+    }
 
-fn note_obligation_cause<T>(&self,
-                            err: &mut DiagnosticBuilder,
-                            obligation: &Obligation<'tcx, T>)
-    where T: fmt::Display
-{
-    self.note_obligation_cause_code(err,
-                                    &obligation.predicate,
-                                    &obligation.cause.code);
-}
+    fn note_obligation_cause<T>(&self,
+                                err: &mut DiagnosticBuilder,
+                                obligation: &Obligation<'tcx, T>)
+        where T: fmt::Display
+    {
+        self.note_obligation_cause_code(err,
+                                        &obligation.predicate,
+                                        &obligation.cause.code);
+    }
 
-fn note_obligation_cause_code<T>(&self,
-                                 err: &mut DiagnosticBuilder,
-                                 predicate: &T,
-                                 cause_code: &ObligationCauseCode<'tcx>)
-    where T: fmt::Display
-{
-    let tcx = self.tcx;
-    match *cause_code {
-        ObligationCauseCode::MiscObligation => { }
-        ObligationCauseCode::SliceOrArrayElem => {
-            err.note("slice and array elements must have `Sized` type");
-        }
-        ObligationCauseCode::TupleElem => {
-            err.note("tuple elements must have `Sized` type");
-        }
-        ObligationCauseCode::ProjectionWf(data) => {
-            err.note(&format!("required so that the projection `{}` is well-formed",
-                              data));
-        }
-        ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
-            err.note(&format!("required so that reference `{}` does not outlive its referent",
-                              ref_ty));
-        }
-        ObligationCauseCode::ItemObligation(item_def_id) => {
-            let item_name = tcx.item_path_str(item_def_id);
-            err.note(&format!("required by `{}`", item_name));
-        }
-        ObligationCauseCode::ObjectCastObligation(object_ty) => {
-            err.note(&format!("required for the cast to the object type `{}`",
-                              self.ty_to_string(object_ty)));
-        }
-        ObligationCauseCode::RepeatVec => {
-            err.note("the `Copy` trait is required because the \
-                      repeated element will be copied");
-        }
-        ObligationCauseCode::VariableType(_) => {
-            err.note("all local variables must have a statically known size");
-        }
-        ObligationCauseCode::ReturnType => {
-            err.note("the return type of a function must have a \
-                      statically known size");
-        }
-        ObligationCauseCode::AssignmentLhsSized => {
-            err.note("the left-hand-side of an assignment must have a statically known size");
-        }
-        ObligationCauseCode::StructInitializerSized => {
-            err.note("structs must have a statically known size to be initialized");
-        }
-        ObligationCauseCode::ClosureCapture(var_id, _, builtin_bound) => {
-            let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap();
-            let trait_name = tcx.item_path_str(def_id);
-            let name = tcx.local_var_name_str(var_id);
-            err.note(
-                &format!("the closure that captures `{}` requires that all captured variables \
-                          implement the trait `{}`",
-                         name,
-                         trait_name));
-        }
-        ObligationCauseCode::FieldSized => {
-            err.note("only the last field of a struct or enum variant \
-                      may have a dynamically sized type");
-        }
-        ObligationCauseCode::SharedStatic => {
-            err.note("shared static variables must have a type that implements `Sync`");
-        }
-        ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
-            let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
-            err.note(&format!("required because it appears within the type `{}`",
-                              parent_trait_ref.0.self_ty()));
-            let parent_predicate = parent_trait_ref.to_predicate();
-            self.note_obligation_cause_code(err,
-                                            &parent_predicate,
-                                            &data.parent_code);
-        }
-        ObligationCauseCode::ImplDerivedObligation(ref data) => {
-            let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
-            err.note(
-                &format!("required because of the requirements on the impl of `{}` for `{}`",
-                         parent_trait_ref,
-                         parent_trait_ref.0.self_ty()));
-            let parent_predicate = parent_trait_ref.to_predicate();
-            self.note_obligation_cause_code(err,
-                                            &parent_predicate,
-                                            &data.parent_code);
-        }
-        ObligationCauseCode::CompareImplMethodObligation => {
-            err.note(
-                &format!("the requirement `{}` appears on the impl method \
-                          but not on the corresponding trait method",
-                         predicate));
+    fn note_obligation_cause_code<T>(&self,
+                                     err: &mut DiagnosticBuilder,
+                                     predicate: &T,
+                                     cause_code: &ObligationCauseCode<'tcx>)
+        where T: fmt::Display
+    {
+        let tcx = self.tcx;
+        match *cause_code {
+            ObligationCauseCode::MiscObligation => { }
+            ObligationCauseCode::SliceOrArrayElem => {
+                err.note("slice and array elements must have `Sized` type");
+            }
+            ObligationCauseCode::TupleElem => {
+                err.note("tuple elements must have `Sized` type");
+            }
+            ObligationCauseCode::ProjectionWf(data) => {
+                err.note(&format!("required so that the projection `{}` is well-formed",
+                                  data));
+            }
+            ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
+                err.note(&format!("required so that reference `{}` does not outlive its referent",
+                                  ref_ty));
+            }
+            ObligationCauseCode::ItemObligation(item_def_id) => {
+                let item_name = tcx.item_path_str(item_def_id);
+                err.note(&format!("required by `{}`", item_name));
+            }
+            ObligationCauseCode::ObjectCastObligation(object_ty) => {
+                err.note(&format!("required for the cast to the object type `{}`",
+                                  self.ty_to_string(object_ty)));
+            }
+            ObligationCauseCode::RepeatVec => {
+                err.note("the `Copy` trait is required because the \
+                          repeated element will be copied");
+            }
+            ObligationCauseCode::VariableType(_) => {
+                err.note("all local variables must have a statically known size");
+            }
+            ObligationCauseCode::ReturnType => {
+                err.note("the return type of a function must have a \
+                          statically known size");
+            }
+            ObligationCauseCode::AssignmentLhsSized => {
+                err.note("the left-hand-side of an assignment must have a statically known size");
+            }
+            ObligationCauseCode::StructInitializerSized => {
+                err.note("structs must have a statically known size to be initialized");
+            }
+            ObligationCauseCode::ClosureCapture(var_id, _, builtin_bound) => {
+                let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap();
+                let trait_name = tcx.item_path_str(def_id);
+                let name = tcx.local_var_name_str(var_id);
+                err.note(
+                    &format!("the closure that captures `{}` requires that all captured variables \
+                              implement the trait `{}`",
+                             name,
+                             trait_name));
+            }
+            ObligationCauseCode::FieldSized => {
+                err.note("only the last field of a struct or enum variant \
+                          may have a dynamically sized type");
+            }
+            ObligationCauseCode::SharedStatic => {
+                err.note("shared static variables must have a type that implements `Sync`");
+            }
+            ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
+                let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
+                err.note(&format!("required because it appears within the type `{}`",
+                                  parent_trait_ref.0.self_ty()));
+                let parent_predicate = parent_trait_ref.to_predicate();
+                self.note_obligation_cause_code(err,
+                                                &parent_predicate,
+                                                &data.parent_code);
+            }
+            ObligationCauseCode::ImplDerivedObligation(ref data) => {
+                let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
+                err.note(
+                    &format!("required because of the requirements on the impl of `{}` for `{}`",
+                             parent_trait_ref,
+                             parent_trait_ref.0.self_ty()));
+                let parent_predicate = parent_trait_ref.to_predicate();
+                self.note_obligation_cause_code(err,
+                                                &parent_predicate,
+                                                &data.parent_code);
+            }
+            ObligationCauseCode::CompareImplMethodObligation => {
+                err.note(
+                    &format!("the requirement `{}` appears on the impl method \
+                              but not on the corresponding trait method",
+                             predicate));
+            }
         }
     }
-}
 
-fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder) {
-    let current_limit = self.tcx.sess.recursion_limit.get();
-    let suggested_limit = current_limit * 2;
-    err.note(&format!(
-                      "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
-                      suggested_limit));
-}
+    fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder) {
+        let current_limit = self.tcx.sess.recursion_limit.get();
+        let suggested_limit = current_limit * 2;
+        err.note(&format!(
+                          "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
+                          suggested_limit));
+    }
 }
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 8fffe3fa666..8cafa779739 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -54,320 +54,320 @@ pub enum MethodViolationCode {
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-pub fn is_object_safe(self, trait_def_id: DefId) -> bool {
-    // Because we query yes/no results frequently, we keep a cache:
-    let def = self.lookup_trait_def(trait_def_id);
+    pub fn is_object_safe(self, trait_def_id: DefId) -> bool {
+        // Because we query yes/no results frequently, we keep a cache:
+        let def = self.lookup_trait_def(trait_def_id);
 
-    let result = def.object_safety().unwrap_or_else(|| {
-        let result = self.object_safety_violations(trait_def_id).is_empty();
+        let result = def.object_safety().unwrap_or_else(|| {
+            let result = self.object_safety_violations(trait_def_id).is_empty();
 
-        // Record just a yes/no result in the cache; this is what is
-        // queried most frequently. Note that this may overwrite a
-        // previous result, but always with the same thing.
-        def.set_object_safety(result);
+            // Record just a yes/no result in the cache; this is what is
+            // queried most frequently. Note that this may overwrite a
+            // previous result, but always with the same thing.
+            def.set_object_safety(result);
+
+            result
+        });
+
+        debug!("is_object_safe({:?}) = {}", trait_def_id, result);
 
         result
-    });
-
-    debug!("is_object_safe({:?}) = {}", trait_def_id, result);
-
-    result
-}
-
-/// Returns the object safety violations that affect
-/// astconv - currently, Self in supertraits. This is needed
-/// because `object_safety_violations` can't be used during
-/// type collection.
-pub fn astconv_object_safety_violations(self, trait_def_id: DefId)
-                                        -> Vec<ObjectSafetyViolation<'tcx>>
-{
-    let mut violations = vec![];
-
-    if self.supertraits_reference_self(trait_def_id) {
-        violations.push(ObjectSafetyViolation::SupertraitSelf);
     }
 
-    debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}",
-           trait_def_id,
-           violations);
+    /// Returns the object safety violations that affect
+    /// astconv - currently, Self in supertraits. This is needed
+    /// because `object_safety_violations` can't be used during
+    /// type collection.
+    pub fn astconv_object_safety_violations(self, trait_def_id: DefId)
+                                            -> Vec<ObjectSafetyViolation<'tcx>>
+    {
+        let mut violations = vec![];
 
-    violations
-}
-
-pub fn object_safety_violations(self, trait_def_id: DefId)
-                                -> Vec<ObjectSafetyViolation<'tcx>>
-{
-    traits::supertrait_def_ids(self, trait_def_id)
-        .flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
-        .collect()
-}
-
-fn object_safety_violations_for_trait(self, trait_def_id: DefId)
-                                      -> Vec<ObjectSafetyViolation<'tcx>>
-{
-    // Check methods for violations.
-    let mut violations: Vec<_> =
-        self.trait_items(trait_def_id).iter()
-        .filter_map(|item| {
-            match *item {
-                ty::MethodTraitItem(ref m) => {
-                    self.object_safety_violation_for_method(trait_def_id, &m)
-                        .map(|code| ObjectSafetyViolation::Method(m.clone(), code))
-                }
-                _ => None,
-            }
-        })
-        .collect();
-
-    // Check the trait itself.
-    if self.trait_has_sized_self(trait_def_id) {
-        violations.push(ObjectSafetyViolation::SizedSelf);
-    }
-    if self.supertraits_reference_self(trait_def_id) {
-        violations.push(ObjectSafetyViolation::SupertraitSelf);
-    }
-
-    debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
-           trait_def_id,
-           violations);
-
-    violations
-}
-
-fn supertraits_reference_self(self, trait_def_id: DefId) -> bool {
-    let trait_def = self.lookup_trait_def(trait_def_id);
-    let trait_ref = trait_def.trait_ref.clone();
-    let trait_ref = trait_ref.to_poly_trait_ref();
-    let predicates = self.lookup_super_predicates(trait_def_id);
-    predicates
-        .predicates
-        .into_iter()
-        .map(|predicate| predicate.subst_supertrait(self, &trait_ref))
-        .any(|predicate| {
-            match predicate {
-                ty::Predicate::Trait(ref data) => {
-                    // In the case of a trait predicate, we can skip the "self" type.
-                    data.0.trait_ref.substs.types.get_slice(TypeSpace)
-                                                 .iter()
-                                                 .cloned()
-                                                 .any(|t| t.has_self_ty())
-                }
-                ty::Predicate::Projection(..) |
-                ty::Predicate::WellFormed(..) |
-                ty::Predicate::ObjectSafe(..) |
-                ty::Predicate::TypeOutlives(..) |
-                ty::Predicate::RegionOutlives(..) |
-                ty::Predicate::ClosureKind(..) |
-                ty::Predicate::Rfc1592(..) |
-                ty::Predicate::Equate(..) => {
-                    false
-                }
-            }
-        })
-}
-
-fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
-    let trait_def = self.lookup_trait_def(trait_def_id);
-    let trait_predicates = self.lookup_predicates(trait_def_id);
-    self.generics_require_sized_self(&trait_def.generics, &trait_predicates)
-}
-
-fn generics_require_sized_self(self,
-                               generics: &ty::Generics<'gcx>,
-                               predicates: &ty::GenericPredicates<'gcx>)
-                               -> bool
-{
-    let sized_def_id = match self.lang_items.sized_trait() {
-        Some(def_id) => def_id,
-        None => { return false; /* No Sized trait, can't require it! */ }
-    };
-
-    // Search for a predicate like `Self : Sized` amongst the trait bounds.
-    let free_substs = self.construct_free_substs(generics,
-        self.region_maps.node_extent(ast::DUMMY_NODE_ID));
-    let predicates = predicates.instantiate(self, &free_substs).predicates.into_vec();
-    elaborate_predicates(self, predicates)
-        .any(|predicate| {
-            match predicate {
-                ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
-                    trait_pred.0.self_ty().is_self()
-                }
-                ty::Predicate::Projection(..) |
-                ty::Predicate::Trait(..) |
-                ty::Predicate::Rfc1592(..) |
-                ty::Predicate::Equate(..) |
-                ty::Predicate::RegionOutlives(..) |
-                ty::Predicate::WellFormed(..) |
-                ty::Predicate::ObjectSafe(..) |
-                ty::Predicate::ClosureKind(..) |
-                ty::Predicate::TypeOutlives(..) => {
-                    false
-                }
-            }
-        })
-}
-
-/// Returns `Some(_)` if this method makes the containing trait not object safe.
-fn object_safety_violation_for_method(self,
-                                      trait_def_id: DefId,
-                                      method: &ty::Method<'gcx>)
-                                      -> Option<MethodViolationCode>
-{
-    // Any method that has a `Self : Sized` requisite is otherwise
-    // exempt from the regulations.
-    if self.generics_require_sized_self(&method.generics, &method.predicates) {
-        return None;
-    }
-
-    self.virtual_call_violation_for_method(trait_def_id, method)
-}
-
-/// We say a method is *vtable safe* if it can be invoked on a trait
-/// object.  Note that object-safe traits can have some
-/// non-vtable-safe methods, so long as they require `Self:Sized` or
-/// otherwise ensure that they cannot be used when `Self=Trait`.
-pub fn is_vtable_safe_method(self,
-                             trait_def_id: DefId,
-                             method: &ty::Method<'tcx>)
-                             -> bool
-{
-    self.virtual_call_violation_for_method(trait_def_id, method).is_none()
-}
-
-/// Returns `Some(_)` if this method cannot be called on a trait
-/// object; this does not necessarily imply that the enclosing trait
-/// is not object safe, because the method might have a where clause
-/// `Self:Sized`.
-fn virtual_call_violation_for_method(self,
-                                     trait_def_id: DefId,
-                                     method: &ty::Method<'tcx>)
-                                     -> Option<MethodViolationCode>
-{
-    // The method's first parameter must be something that derefs (or
-    // autorefs) to `&self`. For now, we only accept `self`, `&self`
-    // and `Box<Self>`.
-    match method.explicit_self {
-        ty::ExplicitSelfCategory::Static => {
-            return Some(MethodViolationCode::StaticMethod);
+        if self.supertraits_reference_self(trait_def_id) {
+            violations.push(ObjectSafetyViolation::SupertraitSelf);
         }
 
-        ty::ExplicitSelfCategory::ByValue |
-        ty::ExplicitSelfCategory::ByReference(..) |
-        ty::ExplicitSelfCategory::ByBox => {
-        }
+        debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}",
+               trait_def_id,
+               violations);
+
+        violations
     }
 
-    // The `Self` type is erased, so it should not appear in list of
-    // arguments or return type apart from the receiver.
-    let ref sig = method.fty.sig;
-    for &input_ty in &sig.0.inputs[1..] {
-        if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
-            return Some(MethodViolationCode::ReferencesSelf);
-        }
-    }
-    if let ty::FnConverging(result_type) = sig.0.output {
-        if self.contains_illegal_self_type_reference(trait_def_id, result_type) {
-            return Some(MethodViolationCode::ReferencesSelf);
-        }
+    pub fn object_safety_violations(self, trait_def_id: DefId)
+                                    -> Vec<ObjectSafetyViolation<'tcx>>
+    {
+        traits::supertrait_def_ids(self, trait_def_id)
+            .flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
+            .collect()
     }
 
-    // We can't monomorphize things like `fn foo<A>(...)`.
-    if !method.generics.types.is_empty_in(subst::FnSpace) {
-        return Some(MethodViolationCode::Generic);
-    }
-
-    None
-}
-
-fn contains_illegal_self_type_reference(self,
-                                        trait_def_id: DefId,
-                                        ty: Ty<'tcx>)
-                                        -> bool
-{
-    // This is somewhat subtle. In general, we want to forbid
-    // references to `Self` in the argument and return types,
-    // since the value of `Self` is erased. However, there is one
-    // exception: it is ok to reference `Self` in order to access
-    // an associated type of the current trait, since we retain
-    // the value of those associated types in the object type
-    // itself.
-    //
-    // ```rust
-    // trait SuperTrait {
-    //     type X;
-    // }
-    //
-    // trait Trait : SuperTrait {
-    //     type Y;
-    //     fn foo(&self, x: Self) // bad
-    //     fn foo(&self) -> Self // bad
-    //     fn foo(&self) -> Option<Self> // bad
-    //     fn foo(&self) -> Self::Y // OK, desugars to next example
-    //     fn foo(&self) -> <Self as Trait>::Y // OK
-    //     fn foo(&self) -> Self::X // OK, desugars to next example
-    //     fn foo(&self) -> <Self as SuperTrait>::X // OK
-    // }
-    // ```
-    //
-    // However, it is not as simple as allowing `Self` in a projected
-    // type, because there are illegal ways to use `Self` as well:
-    //
-    // ```rust
-    // trait Trait : SuperTrait {
-    //     ...
-    //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
-    // }
-    // ```
-    //
-    // Here we will not have the type of `X` recorded in the
-    // object type, and we cannot resolve `Self as SomeOtherTrait`
-    // without knowing what `Self` is.
-
-    let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
-    let mut error = false;
-    ty.maybe_walk(|ty| {
-        match ty.sty {
-            ty::TyParam(ref param_ty) => {
-                if param_ty.space == SelfSpace {
-                    error = true;
+    fn object_safety_violations_for_trait(self, trait_def_id: DefId)
+                                          -> Vec<ObjectSafetyViolation<'tcx>>
+    {
+        // Check methods for violations.
+        let mut violations: Vec<_> =
+            self.trait_items(trait_def_id).iter()
+            .filter_map(|item| {
+                match *item {
+                    ty::MethodTraitItem(ref m) => {
+                        self.object_safety_violation_for_method(trait_def_id, &m)
+                            .map(|code| ObjectSafetyViolation::Method(m.clone(), code))
+                    }
+                    _ => None,
                 }
+            })
+            .collect();
 
-                false // no contained types to walk
+        // Check the trait itself.
+        if self.trait_has_sized_self(trait_def_id) {
+            violations.push(ObjectSafetyViolation::SizedSelf);
+        }
+        if self.supertraits_reference_self(trait_def_id) {
+            violations.push(ObjectSafetyViolation::SupertraitSelf);
+        }
+
+        debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
+               trait_def_id,
+               violations);
+
+        violations
+    }
+
+    fn supertraits_reference_self(self, trait_def_id: DefId) -> bool {
+        let trait_def = self.lookup_trait_def(trait_def_id);
+        let trait_ref = trait_def.trait_ref.clone();
+        let trait_ref = trait_ref.to_poly_trait_ref();
+        let predicates = self.lookup_super_predicates(trait_def_id);
+        predicates
+            .predicates
+            .into_iter()
+            .map(|predicate| predicate.subst_supertrait(self, &trait_ref))
+            .any(|predicate| {
+                match predicate {
+                    ty::Predicate::Trait(ref data) => {
+                        // In the case of a trait predicate, we can skip the "self" type.
+                        data.0.trait_ref.substs.types.get_slice(TypeSpace)
+                                                     .iter()
+                                                     .cloned()
+                                                     .any(|t| t.has_self_ty())
+                    }
+                    ty::Predicate::Projection(..) |
+                    ty::Predicate::WellFormed(..) |
+                    ty::Predicate::ObjectSafe(..) |
+                    ty::Predicate::TypeOutlives(..) |
+                    ty::Predicate::RegionOutlives(..) |
+                    ty::Predicate::ClosureKind(..) |
+                    ty::Predicate::Rfc1592(..) |
+                    ty::Predicate::Equate(..) => {
+                        false
+                    }
+                }
+            })
+    }
+
+    fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
+        let trait_def = self.lookup_trait_def(trait_def_id);
+        let trait_predicates = self.lookup_predicates(trait_def_id);
+        self.generics_require_sized_self(&trait_def.generics, &trait_predicates)
+    }
+
+    fn generics_require_sized_self(self,
+                                   generics: &ty::Generics<'gcx>,
+                                   predicates: &ty::GenericPredicates<'gcx>)
+                                   -> bool
+    {
+        let sized_def_id = match self.lang_items.sized_trait() {
+            Some(def_id) => def_id,
+            None => { return false; /* No Sized trait, can't require it! */ }
+        };
+
+        // Search for a predicate like `Self : Sized` amongst the trait bounds.
+        let free_substs = self.construct_free_substs(generics,
+            self.region_maps.node_extent(ast::DUMMY_NODE_ID));
+        let predicates = predicates.instantiate(self, &free_substs).predicates.into_vec();
+        elaborate_predicates(self, predicates)
+            .any(|predicate| {
+                match predicate {
+                    ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
+                        trait_pred.0.self_ty().is_self()
+                    }
+                    ty::Predicate::Projection(..) |
+                    ty::Predicate::Trait(..) |
+                    ty::Predicate::Rfc1592(..) |
+                    ty::Predicate::Equate(..) |
+                    ty::Predicate::RegionOutlives(..) |
+                    ty::Predicate::WellFormed(..) |
+                    ty::Predicate::ObjectSafe(..) |
+                    ty::Predicate::ClosureKind(..) |
+                    ty::Predicate::TypeOutlives(..) => {
+                        false
+                    }
+                }
+            })
+    }
+
+    /// Returns `Some(_)` if this method makes the containing trait not object safe.
+    fn object_safety_violation_for_method(self,
+                                          trait_def_id: DefId,
+                                          method: &ty::Method<'gcx>)
+                                          -> Option<MethodViolationCode>
+    {
+        // Any method that has a `Self : Sized` requisite is otherwise
+        // exempt from the regulations.
+        if self.generics_require_sized_self(&method.generics, &method.predicates) {
+            return None;
+        }
+
+        self.virtual_call_violation_for_method(trait_def_id, method)
+    }
+
+    /// We say a method is *vtable safe* if it can be invoked on a trait
+    /// object.  Note that object-safe traits can have some
+    /// non-vtable-safe methods, so long as they require `Self:Sized` or
+    /// otherwise ensure that they cannot be used when `Self=Trait`.
+    pub fn is_vtable_safe_method(self,
+                                 trait_def_id: DefId,
+                                 method: &ty::Method<'tcx>)
+                                 -> bool
+    {
+        self.virtual_call_violation_for_method(trait_def_id, method).is_none()
+    }
+
+    /// Returns `Some(_)` if this method cannot be called on a trait
+    /// object; this does not necessarily imply that the enclosing trait
+    /// is not object safe, because the method might have a where clause
+    /// `Self:Sized`.
+    fn virtual_call_violation_for_method(self,
+                                         trait_def_id: DefId,
+                                         method: &ty::Method<'tcx>)
+                                         -> Option<MethodViolationCode>
+    {
+        // The method's first parameter must be something that derefs (or
+        // autorefs) to `&self`. For now, we only accept `self`, `&self`
+        // and `Box<Self>`.
+        match method.explicit_self {
+            ty::ExplicitSelfCategory::Static => {
+                return Some(MethodViolationCode::StaticMethod);
             }
 
-            ty::TyProjection(ref data) => {
-                // This is a projected type `<Foo as SomeTrait>::X`.
-
-                // Compute supertraits of current trait lazily.
-                if supertraits.is_none() {
-                    let trait_def = self.lookup_trait_def(trait_def_id);
-                    let trait_ref = ty::Binder(trait_def.trait_ref.clone());
-                    supertraits = Some(traits::supertraits(self, trait_ref).collect());
-                }
-
-                // Determine whether the trait reference `Foo as
-                // SomeTrait` is in fact a supertrait of the
-                // current trait. In that case, this type is
-                // legal, because the type `X` will be specified
-                // in the object type.  Note that we can just use
-                // direct equality here because all of these types
-                // are part of the formal parameter listing, and
-                // hence there should be no inference variables.
-                let projection_trait_ref = ty::Binder(data.trait_ref.clone());
-                let is_supertrait_of_current_trait =
-                    supertraits.as_ref().unwrap().contains(&projection_trait_ref);
-
-                if is_supertrait_of_current_trait {
-                    false // do not walk contained types, do not report error, do collect $200
-                } else {
-                    true // DO walk contained types, POSSIBLY reporting an error
-                }
+            ty::ExplicitSelfCategory::ByValue |
+            ty::ExplicitSelfCategory::ByReference(..) |
+            ty::ExplicitSelfCategory::ByBox => {
             }
-
-            _ => true, // walk contained types, if any
         }
-    });
 
-    error
-}
+        // The `Self` type is erased, so it should not appear in list of
+        // arguments or return type apart from the receiver.
+        let ref sig = method.fty.sig;
+        for &input_ty in &sig.0.inputs[1..] {
+            if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
+                return Some(MethodViolationCode::ReferencesSelf);
+            }
+        }
+        if let ty::FnConverging(result_type) = sig.0.output {
+            if self.contains_illegal_self_type_reference(trait_def_id, result_type) {
+                return Some(MethodViolationCode::ReferencesSelf);
+            }
+        }
+
+        // We can't monomorphize things like `fn foo<A>(...)`.
+        if !method.generics.types.is_empty_in(subst::FnSpace) {
+            return Some(MethodViolationCode::Generic);
+        }
+
+        None
+    }
+
+    fn contains_illegal_self_type_reference(self,
+                                            trait_def_id: DefId,
+                                            ty: Ty<'tcx>)
+                                            -> bool
+    {
+        // This is somewhat subtle. In general, we want to forbid
+        // references to `Self` in the argument and return types,
+        // since the value of `Self` is erased. However, there is one
+        // exception: it is ok to reference `Self` in order to access
+        // an associated type of the current trait, since we retain
+        // the value of those associated types in the object type
+        // itself.
+        //
+        // ```rust
+        // trait SuperTrait {
+        //     type X;
+        // }
+        //
+        // trait Trait : SuperTrait {
+        //     type Y;
+        //     fn foo(&self, x: Self) // bad
+        //     fn foo(&self) -> Self // bad
+        //     fn foo(&self) -> Option<Self> // bad
+        //     fn foo(&self) -> Self::Y // OK, desugars to next example
+        //     fn foo(&self) -> <Self as Trait>::Y // OK
+        //     fn foo(&self) -> Self::X // OK, desugars to next example
+        //     fn foo(&self) -> <Self as SuperTrait>::X // OK
+        // }
+        // ```
+        //
+        // However, it is not as simple as allowing `Self` in a projected
+        // type, because there are illegal ways to use `Self` as well:
+        //
+        // ```rust
+        // trait Trait : SuperTrait {
+        //     ...
+        //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
+        // }
+        // ```
+        //
+        // Here we will not have the type of `X` recorded in the
+        // object type, and we cannot resolve `Self as SomeOtherTrait`
+        // without knowing what `Self` is.
+
+        let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
+        let mut error = false;
+        ty.maybe_walk(|ty| {
+            match ty.sty {
+                ty::TyParam(ref param_ty) => {
+                    if param_ty.space == SelfSpace {
+                        error = true;
+                    }
+
+                    false // no contained types to walk
+                }
+
+                ty::TyProjection(ref data) => {
+                    // This is a projected type `<Foo as SomeTrait>::X`.
+
+                    // Compute supertraits of current trait lazily.
+                    if supertraits.is_none() {
+                        let trait_def = self.lookup_trait_def(trait_def_id);
+                        let trait_ref = ty::Binder(trait_def.trait_ref.clone());
+                        supertraits = Some(traits::supertraits(self, trait_ref).collect());
+                    }
+
+                    // Determine whether the trait reference `Foo as
+                    // SomeTrait` is in fact a supertrait of the
+                    // current trait. In that case, this type is
+                    // legal, because the type `X` will be specified
+                    // in the object type.  Note that we can just use
+                    // direct equality here because all of these types
+                    // are part of the formal parameter listing, and
+                    // hence there should be no inference variables.
+                    let projection_trait_ref = ty::Binder(data.trait_ref.clone());
+                    let is_supertrait_of_current_trait =
+                        supertraits.as_ref().unwrap().contains(&projection_trait_ref);
+
+                    if is_supertrait_of_current_trait {
+                        false // do not walk contained types, do not report error, do collect $200
+                    } else {
+                        true // DO walk contained types, POSSIBLY reporting an error
+                    }
+                }
+
+                _ => true, // walk contained types, if any
+            }
+        });
+
+        error
+    }
 }
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 55fb8beee01..010add01237 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -393,130 +393,130 @@ pub fn predicate_for_trait_ref<'tcx>(
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-pub fn trait_ref_for_builtin_bound(self,
-    builtin_bound: ty::BuiltinBound,
-    param_ty: Ty<'tcx>)
-    -> Result<ty::TraitRef<'tcx>, ErrorReported>
-{
-    match self.lang_items.from_builtin_kind(builtin_bound) {
-        Ok(def_id) => {
-            Ok(ty::TraitRef {
-                def_id: def_id,
-                substs: self.mk_substs(Substs::empty().with_self_ty(param_ty))
-            })
-        }
-        Err(e) => {
-            self.sess.err(&e);
-            Err(ErrorReported)
-        }
-    }
-}
-
-pub fn predicate_for_trait_def(self,
-    cause: ObligationCause<'tcx>,
-    trait_def_id: DefId,
-    recursion_depth: usize,
-    param_ty: Ty<'tcx>,
-    ty_params: Vec<Ty<'tcx>>)
-    -> PredicateObligation<'tcx>
-{
-    let trait_ref = ty::TraitRef {
-        def_id: trait_def_id,
-        substs: self.mk_substs(Substs::new_trait(ty_params, vec![], param_ty))
-    };
-    predicate_for_trait_ref(cause, trait_ref, recursion_depth)
-}
-
-pub fn predicate_for_builtin_bound(self,
-    cause: ObligationCause<'tcx>,
-    builtin_bound: ty::BuiltinBound,
-    recursion_depth: usize,
-    param_ty: Ty<'tcx>)
-    -> Result<PredicateObligation<'tcx>, ErrorReported>
-{
-    let trait_ref = self.trait_ref_for_builtin_bound(builtin_bound, param_ty)?;
-    Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth))
-}
-
-/// Cast a trait reference into a reference to one of its super
-/// traits; returns `None` if `target_trait_def_id` is not a
-/// supertrait.
-pub fn upcast_choices(self,
-                      source_trait_ref: ty::PolyTraitRef<'tcx>,
-                      target_trait_def_id: DefId)
-                      -> Vec<ty::PolyTraitRef<'tcx>>
-{
-    if source_trait_ref.def_id() == target_trait_def_id {
-        return vec![source_trait_ref]; // shorcut the most common case
-    }
-
-    supertraits(self, source_trait_ref)
-        .filter(|r| r.def_id() == target_trait_def_id)
-        .collect()
-}
-
-/// Given a trait `trait_ref`, returns the number of vtable entries
-/// that come from `trait_ref`, excluding its supertraits. Used in
-/// computing the vtable base for an upcast trait of a trait object.
-pub fn count_own_vtable_entries(self, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
-    let mut entries = 0;
-    // Count number of methods and add them to the total offset.
-    // Skip over associated types and constants.
-    for trait_item in &self.trait_items(trait_ref.def_id())[..] {
-        if let ty::MethodTraitItem(_) = *trait_item {
-            entries += 1;
-        }
-    }
-    entries
-}
-
-/// Given an upcast trait object described by `object`, returns the
-/// index of the method `method_def_id` (which should be part of
-/// `object.upcast_trait_ref`) within the vtable for `object`.
-pub fn get_vtable_index_of_object_method(self,
-                                         object: &super::VtableObjectData<'tcx>,
-                                         method_def_id: DefId) -> usize {
-    // Count number of methods preceding the one we are selecting and
-    // add them to the total offset.
-    // Skip over associated types and constants.
-    let mut entries = object.vtable_base;
-    for trait_item in &self.trait_items(object.upcast_trait_ref.def_id())[..] {
-        if trait_item.def_id() == method_def_id {
-            // The item with the ID we were given really ought to be a method.
-            assert!(match *trait_item {
-                ty::MethodTraitItem(_) => true,
-                _ => false
-            });
-
-            return entries;
-        }
-        if let ty::MethodTraitItem(_) = *trait_item {
-            entries += 1;
+    pub fn trait_ref_for_builtin_bound(self,
+        builtin_bound: ty::BuiltinBound,
+        param_ty: Ty<'tcx>)
+        -> Result<ty::TraitRef<'tcx>, ErrorReported>
+    {
+        match self.lang_items.from_builtin_kind(builtin_bound) {
+            Ok(def_id) => {
+                Ok(ty::TraitRef {
+                    def_id: def_id,
+                    substs: self.mk_substs(Substs::empty().with_self_ty(param_ty))
+                })
+            }
+            Err(e) => {
+                self.sess.err(&e);
+                Err(ErrorReported)
+            }
         }
     }
 
-    bug!("get_vtable_index_of_object_method: {:?} was not found",
-         method_def_id);
-}
+    pub fn predicate_for_trait_def(self,
+        cause: ObligationCause<'tcx>,
+        trait_def_id: DefId,
+        recursion_depth: usize,
+        param_ty: Ty<'tcx>,
+        ty_params: Vec<Ty<'tcx>>)
+        -> PredicateObligation<'tcx>
+    {
+        let trait_ref = ty::TraitRef {
+            def_id: trait_def_id,
+            substs: self.mk_substs(Substs::new_trait(ty_params, vec![], param_ty))
+        };
+        predicate_for_trait_ref(cause, trait_ref, recursion_depth)
+    }
 
-pub fn closure_trait_ref_and_return_type(self,
-    fn_trait_def_id: DefId,
-    self_ty: Ty<'tcx>,
-    sig: &ty::PolyFnSig<'tcx>,
-    tuple_arguments: TupleArgumentsFlag)
-    -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)>
-{
-    let arguments_tuple = match tuple_arguments {
-        TupleArgumentsFlag::No => sig.0.inputs[0],
-        TupleArgumentsFlag::Yes => self.mk_tup(sig.0.inputs.to_vec()),
-    };
-    let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty);
-    let trait_ref = ty::TraitRef {
-        def_id: fn_trait_def_id,
-        substs: self.mk_substs(trait_substs),
-    };
-    ty::Binder((trait_ref, sig.0.output.unwrap_or(self.mk_nil())))
-}
+    pub fn predicate_for_builtin_bound(self,
+        cause: ObligationCause<'tcx>,
+        builtin_bound: ty::BuiltinBound,
+        recursion_depth: usize,
+        param_ty: Ty<'tcx>)
+        -> Result<PredicateObligation<'tcx>, ErrorReported>
+    {
+        let trait_ref = self.trait_ref_for_builtin_bound(builtin_bound, param_ty)?;
+        Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth))
+    }
+
+    /// Cast a trait reference into a reference to one of its super
+    /// traits; returns `None` if `target_trait_def_id` is not a
+    /// supertrait.
+    pub fn upcast_choices(self,
+                          source_trait_ref: ty::PolyTraitRef<'tcx>,
+                          target_trait_def_id: DefId)
+                          -> Vec<ty::PolyTraitRef<'tcx>>
+    {
+        if source_trait_ref.def_id() == target_trait_def_id {
+            return vec![source_trait_ref]; // shorcut the most common case
+        }
+
+        supertraits(self, source_trait_ref)
+            .filter(|r| r.def_id() == target_trait_def_id)
+            .collect()
+    }
+
+    /// Given a trait `trait_ref`, returns the number of vtable entries
+    /// that come from `trait_ref`, excluding its supertraits. Used in
+    /// computing the vtable base for an upcast trait of a trait object.
+    pub fn count_own_vtable_entries(self, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
+        let mut entries = 0;
+        // Count number of methods and add them to the total offset.
+        // Skip over associated types and constants.
+        for trait_item in &self.trait_items(trait_ref.def_id())[..] {
+            if let ty::MethodTraitItem(_) = *trait_item {
+                entries += 1;
+            }
+        }
+        entries
+    }
+
+    /// Given an upcast trait object described by `object`, returns the
+    /// index of the method `method_def_id` (which should be part of
+    /// `object.upcast_trait_ref`) within the vtable for `object`.
+    pub fn get_vtable_index_of_object_method(self,
+                                             object: &super::VtableObjectData<'tcx>,
+                                             method_def_id: DefId) -> usize {
+        // Count number of methods preceding the one we are selecting and
+        // add them to the total offset.
+        // Skip over associated types and constants.
+        let mut entries = object.vtable_base;
+        for trait_item in &self.trait_items(object.upcast_trait_ref.def_id())[..] {
+            if trait_item.def_id() == method_def_id {
+                // The item with the ID we were given really ought to be a method.
+                assert!(match *trait_item {
+                    ty::MethodTraitItem(_) => true,
+                    _ => false
+                });
+
+                return entries;
+            }
+            if let ty::MethodTraitItem(_) = *trait_item {
+                entries += 1;
+            }
+        }
+
+        bug!("get_vtable_index_of_object_method: {:?} was not found",
+             method_def_id);
+    }
+
+    pub fn closure_trait_ref_and_return_type(self,
+        fn_trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+        sig: &ty::PolyFnSig<'tcx>,
+        tuple_arguments: TupleArgumentsFlag)
+        -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)>
+    {
+        let arguments_tuple = match tuple_arguments {
+            TupleArgumentsFlag::No => sig.0.inputs[0],
+            TupleArgumentsFlag::Yes => self.mk_tup(sig.0.inputs.to_vec()),
+        };
+        let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty);
+        let trait_ref = ty::TraitRef {
+            def_id: fn_trait_def_id,
+            substs: self.mk_substs(trait_substs),
+        };
+        ty::Binder((trait_ref, sig.0.output.unwrap_or(self.mk_nil())))
+    }
 }
 
 pub enum TupleArgumentsFlag { Yes, No }
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index 60f8f277d39..9ae3325c258 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -56,156 +56,156 @@ pub enum Component<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-/// Returns all the things that must outlive `'a` for the condition
-/// `ty0: 'a` to hold.
-pub fn outlives_components(&self, ty0: Ty<'tcx>)
-                           -> Vec<Component<'tcx>> {
-    let mut components = vec![];
-    self.compute_components(ty0, &mut components);
-    debug!("components({:?}) = {:?}", ty0, components);
-    components
-}
+    /// Returns all the things that must outlive `'a` for the condition
+    /// `ty0: 'a` to hold.
+    pub fn outlives_components(&self, ty0: Ty<'tcx>)
+                               -> Vec<Component<'tcx>> {
+        let mut components = vec![];
+        self.compute_components(ty0, &mut components);
+        debug!("components({:?}) = {:?}", ty0, components);
+        components
+    }
 
-fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec<Component<'tcx>>) {
-    // Descend through the types, looking for the various "base"
-    // components and collecting them into `out`. This is not written
-    // with `collect()` because of the need to sometimes skip subtrees
-    // in the `subtys` iterator (e.g., when encountering a
-    // projection).
-    match ty.sty {
-        ty::TyClosure(_, ref substs) => {
-            // FIXME(#27086). We do not accumulate from substs, since they
-            // don't represent reachable data. This means that, in
-            // practice, some of the lifetime parameters might not
-            // be in scope when the body runs, so long as there is
-            // no reachable data with that lifetime. For better or
-            // worse, this is consistent with fn types, however,
-            // which can also encapsulate data in this fashion
-            // (though it's somewhat harder, and typically
-            // requires virtual dispatch).
-            //
-            // Note that changing this (in a naive way, at least)
-            // causes regressions for what appears to be perfectly
-            // reasonable code like this:
-            //
-            // ```
-            // fn foo<'a>(p: &Data<'a>) {
-            //    bar(|q: &mut Parser| q.read_addr())
-            // }
-            // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
-            // }
-            // ```
-            //
-            // Note that `p` (and `'a`) are not used in the
-            // closure at all, but to meet the requirement that
-            // the closure type `C: 'static` (so it can be coerced
-            // to the object type), we get the requirement that
-            // `'a: 'static` since `'a` appears in the closure
-            // type `C`.
-            //
-            // A smarter fix might "prune" unused `func_substs` --
-            // this would avoid breaking simple examples like
-            // this, but would still break others (which might
-            // indeed be invalid, depending on your POV). Pruning
-            // would be a subtle process, since we have to see
-            // what func/type parameters are used and unused,
-            // taking into consideration UFCS and so forth.
+    fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec<Component<'tcx>>) {
+        // Descend through the types, looking for the various "base"
+        // components and collecting them into `out`. This is not written
+        // with `collect()` because of the need to sometimes skip subtrees
+        // in the `subtys` iterator (e.g., when encountering a
+        // projection).
+        match ty.sty {
+            ty::TyClosure(_, ref substs) => {
+                // FIXME(#27086). We do not accumulate from substs, since they
+                // don't represent reachable data. This means that, in
+                // practice, some of the lifetime parameters might not
+                // be in scope when the body runs, so long as there is
+                // no reachable data with that lifetime. For better or
+                // worse, this is consistent with fn types, however,
+                // which can also encapsulate data in this fashion
+                // (though it's somewhat harder, and typically
+                // requires virtual dispatch).
+                //
+                // Note that changing this (in a naive way, at least)
+                // causes regressions for what appears to be perfectly
+                // reasonable code like this:
+                //
+                // ```
+                // fn foo<'a>(p: &Data<'a>) {
+                //    bar(|q: &mut Parser| q.read_addr())
+                // }
+                // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
+                // }
+                // ```
+                //
+                // Note that `p` (and `'a`) are not used in the
+                // closure at all, but to meet the requirement that
+                // the closure type `C: 'static` (so it can be coerced
+                // to the object type), we get the requirement that
+                // `'a: 'static` since `'a` appears in the closure
+                // type `C`.
+                //
+                // A smarter fix might "prune" unused `func_substs` --
+                // this would avoid breaking simple examples like
+                // this, but would still break others (which might
+                // indeed be invalid, depending on your POV). Pruning
+                // would be a subtle process, since we have to see
+                // what func/type parameters are used and unused,
+                // taking into consideration UFCS and so forth.
 
-            for &upvar_ty in substs.upvar_tys {
-                self.compute_components(upvar_ty, out);
+                for &upvar_ty in substs.upvar_tys {
+                    self.compute_components(upvar_ty, out);
+                }
             }
-        }
 
-        // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
-        // is implied by the environment is done in regionck.
-        ty::TyParam(p) => {
-            out.push(Component::Param(p));
-        }
-
-        // For projections, we prefer to generate an obligation like
-        // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
-        // regionck more ways to prove that it holds. However,
-        // regionck is not (at least currently) prepared to deal with
-        // higher-ranked regions that may appear in the
-        // trait-ref. Therefore, if we see any higher-ranke regions,
-        // we simply fallback to the most restrictive rule, which
-        // requires that `Pi: 'a` for all `i`.
-        ty::TyProjection(ref data) => {
-            if !data.has_escaping_regions() {
-                // best case: no escaping regions, so push the
-                // projection and skip the subtree (thus generating no
-                // constraints for Pi). This defers the choice between
-                // the rules OutlivesProjectionEnv,
-                // OutlivesProjectionTraitDef, and
-                // OutlivesProjectionComponents to regionck.
-                out.push(Component::Projection(*data));
-            } else {
-                // fallback case: hard code
-                // OutlivesProjectionComponents.  Continue walking
-                // through and constrain Pi.
-                let subcomponents = self.capture_components(ty);
-                out.push(Component::EscapingProjection(subcomponents));
+            // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
+            // is implied by the environment is done in regionck.
+            ty::TyParam(p) => {
+                out.push(Component::Param(p));
             }
-        }
 
-        // If we encounter an inference variable, try to resolve it
-        // and proceed with resolved version. If we cannot resolve it,
-        // then record the unresolved variable as a component.
-        ty::TyInfer(_) => {
-            let ty = self.resolve_type_vars_if_possible(&ty);
-            if let ty::TyInfer(infer_ty) = ty.sty {
-                out.push(Component::UnresolvedInferenceVariable(infer_ty));
-            } else {
-                self.compute_components(ty, out);
+            // For projections, we prefer to generate an obligation like
+            // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
+            // regionck more ways to prove that it holds. However,
+            // regionck is not (at least currently) prepared to deal with
+            // higher-ranked regions that may appear in the
+            // trait-ref. Therefore, if we see any higher-ranke regions,
+            // we simply fallback to the most restrictive rule, which
+            // requires that `Pi: 'a` for all `i`.
+            ty::TyProjection(ref data) => {
+                if !data.has_escaping_regions() {
+                    // best case: no escaping regions, so push the
+                    // projection and skip the subtree (thus generating no
+                    // constraints for Pi). This defers the choice between
+                    // the rules OutlivesProjectionEnv,
+                    // OutlivesProjectionTraitDef, and
+                    // OutlivesProjectionComponents to regionck.
+                    out.push(Component::Projection(*data));
+                } else {
+                    // fallback case: hard code
+                    // OutlivesProjectionComponents.  Continue walking
+                    // through and constrain Pi.
+                    let subcomponents = self.capture_components(ty);
+                    out.push(Component::EscapingProjection(subcomponents));
+                }
             }
-        }
 
-        // Most types do not introduce any region binders, nor
-        // involve any other subtle cases, and so the WF relation
-        // simply constraints any regions referenced directly by
-        // the type and then visits the types that are lexically
-        // contained within. (The comments refer to relevant rules
-        // from RFC1214.)
-        ty::TyBool |            // OutlivesScalar
-        ty::TyChar |            // OutlivesScalar
-        ty::TyInt(..) |         // OutlivesScalar
-        ty::TyUint(..) |        // OutlivesScalar
-        ty::TyFloat(..) |       // OutlivesScalar
-        ty::TyEnum(..) |        // OutlivesNominalType
-        ty::TyStruct(..) |      // OutlivesNominalType
-        ty::TyBox(..) |         // OutlivesNominalType (ish)
-        ty::TyStr |             // OutlivesScalar (ish)
-        ty::TyArray(..) |       // ...
-        ty::TySlice(..) |       // ...
-        ty::TyRawPtr(..) |      // ...
-        ty::TyRef(..) |         // OutlivesReference
-        ty::TyTuple(..) |       // ...
-        ty::TyFnDef(..) |       // OutlivesFunction (*)
-        ty::TyFnPtr(_) |        // OutlivesFunction (*)
-        ty::TyTrait(..) |       // OutlivesObject, OutlivesFragment (*)
-        ty::TyError => {
-            // (*) Bare functions and traits are both binders. In the
-            // RFC, this means we would add the bound regions to the
-            // "bound regions list".  In our representation, no such
-            // list is maintained explicitly, because bound regions
-            // themselves can be readily identified.
+            // If we encounter an inference variable, try to resolve it
+            // and proceed with resolved version. If we cannot resolve it,
+            // then record the unresolved variable as a component.
+            ty::TyInfer(_) => {
+                let ty = self.resolve_type_vars_if_possible(&ty);
+                if let ty::TyInfer(infer_ty) = ty.sty {
+                    out.push(Component::UnresolvedInferenceVariable(infer_ty));
+                } else {
+                    self.compute_components(ty, out);
+                }
+            }
 
-            push_region_constraints(out, ty.regions());
-            for subty in ty.walk_shallow() {
-                self.compute_components(subty, out);
+            // Most types do not introduce any region binders, nor
+            // involve any other subtle cases, and so the WF relation
+            // simply constraints any regions referenced directly by
+            // the type and then visits the types that are lexically
+            // contained within. (The comments refer to relevant rules
+            // from RFC1214.)
+            ty::TyBool |            // OutlivesScalar
+            ty::TyChar |            // OutlivesScalar
+            ty::TyInt(..) |         // OutlivesScalar
+            ty::TyUint(..) |        // OutlivesScalar
+            ty::TyFloat(..) |       // OutlivesScalar
+            ty::TyEnum(..) |        // OutlivesNominalType
+            ty::TyStruct(..) |      // OutlivesNominalType
+            ty::TyBox(..) |         // OutlivesNominalType (ish)
+            ty::TyStr |             // OutlivesScalar (ish)
+            ty::TyArray(..) |       // ...
+            ty::TySlice(..) |       // ...
+            ty::TyRawPtr(..) |      // ...
+            ty::TyRef(..) |         // OutlivesReference
+            ty::TyTuple(..) |       // ...
+            ty::TyFnDef(..) |       // OutlivesFunction (*)
+            ty::TyFnPtr(_) |        // OutlivesFunction (*)
+            ty::TyTrait(..) |       // OutlivesObject, OutlivesFragment (*)
+            ty::TyError => {
+                // (*) Bare functions and traits are both binders. In the
+                // RFC, this means we would add the bound regions to the
+                // "bound regions list".  In our representation, no such
+                // list is maintained explicitly, because bound regions
+                // themselves can be readily identified.
+
+                push_region_constraints(out, ty.regions());
+                for subty in ty.walk_shallow() {
+                    self.compute_components(subty, out);
+                }
             }
         }
     }
-}
 
-fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
-    let mut temp = vec![];
-    push_region_constraints(&mut temp, ty.regions());
-    for subty in ty.walk_shallow() {
-        self.compute_components(subty, &mut temp);
+    fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
+        let mut temp = vec![];
+        push_region_constraints(&mut temp, ty.regions());
+        for subty in ty.walk_shallow() {
+            self.compute_components(subty, &mut temp);
+        }
+        temp
     }
-    temp
-}
 }
 
 fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region>) {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index b6f1e86780b..725d40889ce 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -276,1806 +276,1815 @@ fn report_elision_failure(
 }
 
 impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
-pub fn opt_ast_region_to_region(&self,
-    rscope: &RegionScope,
-    default_span: Span,
-    opt_lifetime: &Option<hir::Lifetime>) -> ty::Region
-{
-    let r = match *opt_lifetime {
-        Some(ref lifetime) => {
-            ast_region_to_region(self.tcx(), lifetime)
-        }
-
-        None => match rscope.anon_regions(default_span, 1) {
-            Ok(rs) => rs[0],
-            Err(params) => {
-                let mut err = struct_span_err!(self.tcx().sess, default_span, E0106,
-                                               "missing lifetime specifier");
-                if let Some(params) = params {
-                    report_elision_failure(&mut err, params);
-                }
-                err.emit();
-                ty::ReStatic
-            }
-        }
-    };
-
-    debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}",
-            opt_lifetime,
-            r);
-
-    r
-}
-
-/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
-/// returns an appropriate set of substitutions for this particular reference to `I`.
-pub fn ast_path_substs_for_ty(&self,
-    rscope: &RegionScope,
-    span: Span,
-    param_mode: PathParamMode,
-    decl_generics: &ty::Generics<'tcx>,
-    item_segment: &hir::PathSegment)
-    -> Substs<'tcx>
-{
-    let tcx = self.tcx();
-
-    // ast_path_substs() is only called to convert paths that are
-    // known to refer to traits, types, or structs. In these cases,
-    // all type parameters defined for the item being referenced will
-    // be in the TypeSpace or SelfSpace.
-    //
-    // Note: in the case of traits, the self parameter is also
-    // defined, but we don't currently create a `type_param_def` for
-    // `Self` because it is implicit.
-    assert!(decl_generics.regions.all(|d| d.space == TypeSpace));
-    assert!(decl_generics.types.all(|d| d.space != FnSpace));
-
-    let (regions, types, assoc_bindings) = match item_segment.parameters {
-        hir::AngleBracketedParameters(ref data) => {
-            self.convert_angle_bracketed_parameters(rscope, span, decl_generics, data)
-        }
-        hir::ParenthesizedParameters(..) => {
-            span_err!(tcx.sess, span, E0214,
-                      "parenthesized parameters may only be used with a trait");
-            let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
-            (Substs::empty(),
-             ty_param_defs.iter().map(|_| tcx.types.err).collect(),
-             vec![])
-        }
-    };
-
-    assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
-
-    self.create_substs_for_ast_path(span,
-                                    param_mode,
-                                    decl_generics,
-                                    None,
-                                    types,
-                                    regions)
-}
-
-fn create_region_substs(&self,
-    rscope: &RegionScope,
-    span: Span,
-    decl_generics: &ty::Generics<'tcx>,
-    regions_provided: Vec<ty::Region>)
-    -> Substs<'tcx>
-{
-    let tcx = self.tcx();
-
-    // If the type is parameterized by this region, then replace this
-    // region with the current anon region binding (in other words,
-    // whatever & would get replaced with).
-    let expected_num_region_params = decl_generics.regions.len(TypeSpace);
-    let supplied_num_region_params = regions_provided.len();
-    let regions = if expected_num_region_params == supplied_num_region_params {
-        regions_provided
-    } else {
-        let anon_regions =
-            rscope.anon_regions(span, expected_num_region_params);
-
-        if supplied_num_region_params != 0 || anon_regions.is_err() {
-            report_lifetime_number_error(tcx, span,
-                                         supplied_num_region_params,
-                                         expected_num_region_params);
-        }
-
-        match anon_regions {
-            Ok(anon_regions) => anon_regions,
-            Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect()
-        }
-    };
-    Substs::new_type(vec![], regions)
-}
-
-/// Given the type/region arguments provided to some path (along with
-/// an implicit Self, if this is a trait reference) returns the complete
-/// set of substitutions. This may involve applying defaulted type parameters.
-///
-/// Note that the type listing given here is *exactly* what the user provided.
-///
-/// The `region_substs` should be the result of `create_region_substs`
-/// -- that is, a substitution with no types but the correct number of
-/// regions.
-fn create_substs_for_ast_path(&self,
-    span: Span,
-    param_mode: PathParamMode,
-    decl_generics: &ty::Generics<'tcx>,
-    self_ty: Option<Ty<'tcx>>,
-    types_provided: Vec<Ty<'tcx>>,
-    region_substs: Substs<'tcx>)
-    -> Substs<'tcx>
-{
-    let tcx = self.tcx();
-
-    debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \
-           types_provided={:?}, region_substs={:?})",
-           decl_generics, self_ty, types_provided,
-           region_substs);
-
-    assert_eq!(region_substs.regions.len(TypeSpace), decl_generics.regions.len(TypeSpace));
-    assert!(region_substs.types.is_empty());
-
-    // Convert the type parameters supplied by the user.
-    let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
-    let formal_ty_param_count = ty_param_defs.len();
-    let required_ty_param_count = ty_param_defs.iter()
-                                               .take_while(|x| x.default.is_none())
-                                               .count();
-
-    let mut type_substs = self.get_type_substs_for_defs(span,
-                                                        types_provided,
-                                                        param_mode,
-                                                        ty_param_defs,
-                                                        region_substs.clone(),
-                                                        self_ty);
-
-    let supplied_ty_param_count = type_substs.len();
-    check_type_argument_count(self.tcx(), span, supplied_ty_param_count,
-                              required_ty_param_count, formal_ty_param_count);
-
-    if supplied_ty_param_count < required_ty_param_count {
-        while type_substs.len() < required_ty_param_count {
-            type_substs.push(tcx.types.err);
-        }
-    } else if supplied_ty_param_count > formal_ty_param_count {
-        type_substs.truncate(formal_ty_param_count);
-    }
-    assert!(type_substs.len() >= required_ty_param_count &&
-            type_substs.len() <= formal_ty_param_count);
-
-    let mut substs = region_substs;
-    substs.types.extend(TypeSpace, type_substs.into_iter());
-
-    match self_ty {
-        None => {
-            // If no self-type is provided, it's still possible that
-            // one was declared, because this could be an object type.
-        }
-        Some(ty) => {
-            // If a self-type is provided, one should have been
-            // "declared" (in other words, this should be a
-            // trait-ref).
-            assert!(decl_generics.types.get_self().is_some());
-            substs.types.push(SelfSpace, ty);
-        }
-    }
-
-    let actual_supplied_ty_param_count = substs.types.len(TypeSpace);
-    for param in &ty_param_defs[actual_supplied_ty_param_count..] {
-        if let Some(default) = param.default {
-            // If we are converting an object type, then the
-            // `Self` parameter is unknown. However, some of the
-            // other type parameters may reference `Self` in their
-            // defaults. This will lead to an ICE if we are not
-            // careful!
-            if self_ty.is_none() && default.has_self_ty() {
-                span_err!(tcx.sess, span, E0393,
-                          "the type parameter `{}` must be explicitly specified \
-                           in an object type because its default value `{}` references \
-                           the type `Self`",
-                          param.name,
-                          default);
-                substs.types.push(TypeSpace, tcx.types.err);
-            } else {
-                // This is a default type parameter.
-                let default = default.subst_spanned(tcx,
-                                                    &substs,
-                                                    Some(span));
-                substs.types.push(TypeSpace, default);
-            }
-        } else {
-            span_bug!(span, "extra parameter without default");
-        }
-    }
-
-    debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}",
-           decl_generics, self_ty, substs);
-
-    substs
-}
-
-/// Returns types_provided if it is not empty, otherwise populating the
-/// type parameters with inference variables as appropriate.
-fn get_type_substs_for_defs(&self,
-                            span: Span,
-                            types_provided: Vec<Ty<'tcx>>,
-                            param_mode: PathParamMode,
-                            ty_param_defs: &[ty::TypeParameterDef<'tcx>],
-                            mut substs: Substs<'tcx>,
-                            self_ty: Option<Ty<'tcx>>)
-                            -> Vec<Ty<'tcx>>
-{
-    fn default_type_parameter<'tcx>(p: &ty::TypeParameterDef<'tcx>, self_ty: Option<Ty<'tcx>>)
-                                    -> Option<ty::TypeParameterDef<'tcx>>
+    pub fn opt_ast_region_to_region(&self,
+        rscope: &RegionScope,
+        default_span: Span,
+        opt_lifetime: &Option<hir::Lifetime>) -> ty::Region
     {
-        if let Some(ref default) = p.default {
-            if self_ty.is_none() && default.has_self_ty() {
-                // There is no suitable inference default for a type parameter
-                // that references self with no self-type provided.
-                return None;
-            }
-        }
-
-        Some(p.clone())
-    }
-
-    if param_mode == PathParamMode::Optional && types_provided.is_empty() {
-        ty_param_defs
-            .iter()
-            .map(|p| self.ty_infer(default_type_parameter(p, self_ty), Some(&mut substs),
-                                   Some(TypeSpace), span))
-            .collect()
-    } else {
-        types_provided
-    }
-}
-
-fn convert_angle_bracketed_parameters(&self,
-                                      rscope: &RegionScope,
-                                      span: Span,
-                                      decl_generics: &ty::Generics<'tcx>,
-                                      data: &hir::AngleBracketedParameterData)
-                                      -> (Substs<'tcx>,
-                                          Vec<Ty<'tcx>>,
-                                          Vec<ConvertedBinding<'tcx>>)
-{
-    let regions: Vec<_> =
-        data.lifetimes.iter()
-                      .map(|l| ast_region_to_region(self.tcx(), l))
-                      .collect();
-
-    let region_substs =
-        self.create_region_substs(rscope, span, decl_generics, regions);
-
-    let types: Vec<_> =
-        data.types.iter()
-                  .enumerate()
-                  .map(|(i,t)| self.ast_ty_arg_to_ty(rscope, decl_generics,
-                                                     i, &region_substs, t))
-                  .collect();
-
-    let assoc_bindings: Vec<_> =
-        data.bindings.iter()
-                     .map(|b| ConvertedBinding { item_name: b.name,
-                                                 ty: self.ast_ty_to_ty(rscope, &b.ty),
-                                                 span: b.span })
-                     .collect();
-
-    (region_substs, types, assoc_bindings)
-}
-
-/// Returns the appropriate lifetime to use for any output lifetimes
-/// (if one exists) and a vector of the (pattern, number of lifetimes)
-/// corresponding to each input type/pattern.
-fn find_implied_output_region(&self,
-                              input_tys: &[Ty<'tcx>],
-                              input_pats: Vec<String>) -> ElidedLifetime
-{
-    let tcx = self.tcx();
-    let mut lifetimes_for_params = Vec::new();
-    let mut possible_implied_output_region = None;
-
-    for (input_type, input_pat) in input_tys.iter().zip(input_pats) {
-        let mut regions = FnvHashSet();
-        let have_bound_regions = tcx.collect_regions(input_type, &mut regions);
-
-        debug!("find_implied_output_regions: collected {:?} from {:?} \
-                have_bound_regions={:?}", &regions, input_type, have_bound_regions);
-
-        if regions.len() == 1 {
-            // there's a chance that the unique lifetime of this
-            // iteration will be the appropriate lifetime for output
-            // parameters, so lets store it.
-            possible_implied_output_region = regions.iter().cloned().next();
-        }
-
-        lifetimes_for_params.push(ElisionFailureInfo {
-            name: input_pat,
-            lifetime_count: regions.len(),
-            have_bound_regions: have_bound_regions
-        });
-    }
-
-    if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::<usize>() == 1 {
-        Ok(possible_implied_output_region.unwrap())
-    } else {
-        Err(Some(lifetimes_for_params))
-    }
-}
-
-fn convert_ty_with_lifetime_elision(&self,
-                                    elided_lifetime: ElidedLifetime,
-                                    ty: &hir::Ty)
-                                    -> Ty<'tcx>
-{
-    match elided_lifetime {
-        Ok(implied_output_region) => {
-            let rb = ElidableRscope::new(implied_output_region);
-            self.ast_ty_to_ty(&rb, ty)
-        }
-        Err(param_lifetimes) => {
-            // All regions must be explicitly specified in the output
-            // if the lifetime elision rules do not apply. This saves
-            // the user from potentially-confusing errors.
-            let rb = UnelidableRscope::new(param_lifetimes);
-            self.ast_ty_to_ty(&rb, ty)
-        }
-    }
-}
-
-fn convert_parenthesized_parameters(&self,
-                                    rscope: &RegionScope,
-                                    span: Span,
-                                    decl_generics: &ty::Generics<'tcx>,
-                                    data: &hir::ParenthesizedParameterData)
-                                    -> (Substs<'tcx>,
-                                        Vec<Ty<'tcx>>,
-                                        Vec<ConvertedBinding<'tcx>>)
-{
-    let region_substs =
-        self.create_region_substs(rscope, span, decl_generics, Vec::new());
-
-    let binding_rscope = BindingRscope::new();
-    let inputs =
-        data.inputs.iter()
-                   .map(|a_t| self.ast_ty_arg_to_ty(&binding_rscope, decl_generics,
-                                                    0, &region_substs, a_t))
-                   .collect::<Vec<Ty<'tcx>>>();
-
-    let input_params = vec![String::new(); inputs.len()];
-    let implied_output_region = self.find_implied_output_region(&inputs, input_params);
-
-    let input_ty = self.tcx().mk_tup(inputs);
-
-    let (output, output_span) = match data.output {
-        Some(ref output_ty) => {
-            (self.convert_ty_with_lifetime_elision(implied_output_region, &output_ty),
-             output_ty.span)
-        }
-        None => {
-            (self.tcx().mk_nil(), data.span)
-        }
-    };
-
-    let output_binding = ConvertedBinding {
-        item_name: token::intern(FN_OUTPUT_NAME),
-        ty: output,
-        span: output_span
-    };
-
-    (region_substs, vec![input_ty], vec![output_binding])
-}
-
-pub fn instantiate_poly_trait_ref(&self,
-    rscope: &RegionScope,
-    ast_trait_ref: &hir::PolyTraitRef,
-    self_ty: Option<Ty<'tcx>>,
-    poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-    -> ty::PolyTraitRef<'tcx>
-{
-    let trait_ref = &ast_trait_ref.trait_ref;
-    let trait_def_id = self.trait_def_id(trait_ref);
-    self.ast_path_to_poly_trait_ref(rscope,
-                                    trait_ref.path.span,
-                                    PathParamMode::Explicit,
-                                    trait_def_id,
-                                    self_ty,
-                                    trait_ref.path.segments.last().unwrap(),
-                                    poly_projections)
-}
-
-/// Instantiates the path for the given trait reference, assuming that it's
-/// bound to a valid trait type. Returns the def_id for the defining trait.
-/// Fails if the type is a type other than a trait type.
-///
-/// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
-/// are disallowed. Otherwise, they are pushed onto the vector given.
-pub fn instantiate_mono_trait_ref(&self,
-    rscope: &RegionScope,
-    trait_ref: &hir::TraitRef,
-    self_ty: Option<Ty<'tcx>>)
-    -> ty::TraitRef<'tcx>
-{
-    let trait_def_id = self.trait_def_id(trait_ref);
-    self.ast_path_to_mono_trait_ref(rscope,
-                                    trait_ref.path.span,
-                                    PathParamMode::Explicit,
-                                    trait_def_id,
-                                    self_ty,
-                                    trait_ref.path.segments.last().unwrap())
-}
-
-fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId {
-    let path = &trait_ref.path;
-    match ::lookup_full_def(self.tcx(), path.span, trait_ref.ref_id) {
-        Def::Trait(trait_def_id) => trait_def_id,
-        Def::Err => {
-            self.tcx().sess.fatal("cannot continue compilation due to previous error");
-        }
-        _ => {
-            span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait",
-                        path);
-        }
-    }
-}
-
-fn object_path_to_poly_trait_ref(&self,
-    rscope: &RegionScope,
-    span: Span,
-    param_mode: PathParamMode,
-    trait_def_id: DefId,
-    trait_segment: &hir::PathSegment,
-    mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-    -> ty::PolyTraitRef<'tcx>
-{
-    self.ast_path_to_poly_trait_ref(rscope,
-                                    span,
-                                    param_mode,
-                                    trait_def_id,
-                                    None,
-                                    trait_segment,
-                                    projections)
-}
-
-fn ast_path_to_poly_trait_ref(&self,
-    rscope: &RegionScope,
-    span: Span,
-    param_mode: PathParamMode,
-    trait_def_id: DefId,
-    self_ty: Option<Ty<'tcx>>,
-    trait_segment: &hir::PathSegment,
-    poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-    -> ty::PolyTraitRef<'tcx>
-{
-    debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment);
-    // The trait reference introduces a binding level here, so
-    // we need to shift the `rscope`. It'd be nice if we could
-    // do away with this rscope stuff and work this knowledge
-    // into resolve_lifetimes, as we do with non-omitted
-    // lifetimes. Oh well, not there yet.
-    let shifted_rscope = &ShiftedRscope::new(rscope);
-
-    let (substs, assoc_bindings) =
-        self.create_substs_for_ast_trait_ref(shifted_rscope,
-                                             span,
-                                             param_mode,
-                                             trait_def_id,
-                                             self_ty,
-                                             trait_segment);
-    let poly_trait_ref = ty::Binder(ty::TraitRef::new(trait_def_id, substs));
-
-    {
-        let converted_bindings =
-            assoc_bindings
-            .iter()
-            .filter_map(|binding| {
-                // specify type to assert that error was already reported in Err case:
-                let predicate: Result<_, ErrorReported> =
-                    self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref.clone(),
-                                                                       self_ty,
-                                                                       binding);
-                predicate.ok() // ok to ignore Err() because ErrorReported (see above)
-            });
-        poly_projections.extend(converted_bindings);
-    }
-
-    debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}",
-           trait_segment, poly_projections, poly_trait_ref);
-    poly_trait_ref
-}
-
-fn ast_path_to_mono_trait_ref(&self,
-                              rscope: &RegionScope,
-                              span: Span,
-                              param_mode: PathParamMode,
-                              trait_def_id: DefId,
-                              self_ty: Option<Ty<'tcx>>,
-                              trait_segment: &hir::PathSegment)
-                              -> ty::TraitRef<'tcx>
-{
-    let (substs, assoc_bindings) =
-        self.create_substs_for_ast_trait_ref(rscope,
-                                             span,
-                                             param_mode,
-                                             trait_def_id,
-                                             self_ty,
-                                             trait_segment);
-    assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
-    ty::TraitRef::new(trait_def_id, substs)
-}
-
-fn create_substs_for_ast_trait_ref(&self,
-                                   rscope: &RegionScope,
-                                   span: Span,
-                                   param_mode: PathParamMode,
-                                   trait_def_id: DefId,
-                                   self_ty: Option<Ty<'tcx>>,
-                                   trait_segment: &hir::PathSegment)
-                                   -> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
-{
-    debug!("create_substs_for_ast_trait_ref(trait_segment={:?})",
-           trait_segment);
-
-    let trait_def = match self.get_trait_def(span, trait_def_id) {
-        Ok(trait_def) => trait_def,
-        Err(ErrorReported) => {
-            // No convenient way to recover from a cycle here. Just bail. Sorry!
-            self.tcx().sess.abort_if_errors();
-            bug!("ErrorReported returned, but no errors reports?")
-        }
-    };
-
-    let (regions, types, assoc_bindings) = match trait_segment.parameters {
-        hir::AngleBracketedParameters(ref data) => {
-            // For now, require that parenthetical notation be used
-            // only with `Fn()` etc.
-            if !self.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar {
-                emit_feature_err(&self.tcx().sess.parse_sess.span_diagnostic,
-                                 "unboxed_closures", span, GateIssue::Language,
-                                 "\
-                    the precise format of `Fn`-family traits' type parameters is \
-                    subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead");
+        let r = match *opt_lifetime {
+            Some(ref lifetime) => {
+                ast_region_to_region(self.tcx(), lifetime)
             }
 
-            self.convert_angle_bracketed_parameters(rscope, span, &trait_def.generics, data)
-        }
-        hir::ParenthesizedParameters(ref data) => {
-            // For now, require that parenthetical notation be used
-            // only with `Fn()` etc.
-            if !self.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar {
-                emit_feature_err(&self.tcx().sess.parse_sess.span_diagnostic,
-                                 "unboxed_closures", span, GateIssue::Language,
-                                 "\
-                    parenthetical notation is only stable when used with `Fn`-family traits");
-            }
-
-            self.convert_parenthesized_parameters(rscope, span, &trait_def.generics, data)
-        }
-    };
-
-    let substs = self.create_substs_for_ast_path(span,
-                                                 param_mode,
-                                                 &trait_def.generics,
-                                                 self_ty,
-                                                 types,
-                                                 regions);
-
-    (self.tcx().mk_substs(substs), assoc_bindings)
-}
-
-fn ast_type_binding_to_poly_projection_predicate(&self,
-    mut trait_ref: ty::PolyTraitRef<'tcx>,
-    self_ty: Option<Ty<'tcx>>,
-    binding: &ConvertedBinding<'tcx>)
-    -> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
-{
-    let tcx = self.tcx();
-
-    // Given something like `U : SomeTrait<T=X>`, we want to produce a
-    // predicate like `<U as SomeTrait>::T = X`. This is somewhat
-    // subtle in the event that `T` is defined in a supertrait of
-    // `SomeTrait`, because in that case we need to upcast.
-    //
-    // That is, consider this case:
-    //
-    // ```
-    // trait SubTrait : SuperTrait<int> { }
-    // trait SuperTrait<A> { type T; }
-    //
-    // ... B : SubTrait<T=foo> ...
-    // ```
-    //
-    // We want to produce `<B as SuperTrait<int>>::T == foo`.
-
-    // Simple case: X is defined in the current trait.
-    if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
-        return Ok(ty::Binder(ty::ProjectionPredicate {      // <-------------------+
-            projection_ty: ty::ProjectionTy {               //                     |
-                trait_ref: trait_ref.skip_binder().clone(), // Binder moved here --+
-                item_name: binding.item_name,
-            },
-            ty: binding.ty,
-        }));
-    }
-
-    // Otherwise, we have to walk through the supertraits to find
-    // those that do.  This is complicated by the fact that, for an
-    // object type, the `Self` type is not present in the
-    // substitutions (after all, it's being constructed right now),
-    // but the `supertraits` iterator really wants one. To handle
-    // this, we currently insert a dummy type and then remove it
-    // later. Yuck.
-
-    let dummy_self_ty = tcx.mk_infer(ty::FreshTy(0));
-    if self_ty.is_none() { // if converting for an object type
-        let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+
-        assert!(dummy_substs.self_ty().is_none());                     //                    |
-        dummy_substs.types.push(SelfSpace, dummy_self_ty);             //                    |
-        trait_ref = ty::Binder(ty::TraitRef::new(trait_ref.def_id(),   // <------------+
-                                                 tcx.mk_substs(dummy_substs)));
-    }
-
-    self.ensure_super_predicates(binding.span, trait_ref.def_id())?;
-
-    let mut candidates: Vec<ty::PolyTraitRef> =
-        traits::supertraits(tcx, trait_ref.clone())
-        .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name))
-        .collect();
-
-    // If converting for an object type, then remove the dummy-ty from `Self` now.
-    // Yuckety yuck.
-    if self_ty.is_none() {
-        for candidate in &mut candidates {
-            let mut dummy_substs = candidate.0.substs.clone();
-            assert!(dummy_substs.self_ty() == Some(dummy_self_ty));
-            dummy_substs.types.pop(SelfSpace);
-            *candidate = ty::Binder(ty::TraitRef::new(candidate.def_id(),
-                                                      tcx.mk_substs(dummy_substs)));
-        }
-    }
-
-    let candidate = self.one_bound_for_assoc_type(candidates,
-                                                  &trait_ref.to_string(),
-                                                  &binding.item_name.as_str(),
-                                                  binding.span)?;
-
-    Ok(ty::Binder(ty::ProjectionPredicate {             // <-------------------------+
-        projection_ty: ty::ProjectionTy {               //                           |
-            trait_ref: candidate.skip_binder().clone(), // binder is moved up here --+
-            item_name: binding.item_name,
-        },
-        ty: binding.ty,
-    }))
-}
-
-fn ast_path_to_ty(&self,
-    rscope: &RegionScope,
-    span: Span,
-    param_mode: PathParamMode,
-    did: DefId,
-    item_segment: &hir::PathSegment)
-    -> Ty<'tcx>
-{
-    let tcx = self.tcx();
-    let (generics, decl_ty) = match self.get_item_type_scheme(span, did) {
-        Ok(ty::TypeScheme { generics,  ty: decl_ty }) => {
-            (generics, decl_ty)
-        }
-        Err(ErrorReported) => {
-            return tcx.types.err;
-        }
-    };
-
-    let substs = self.ast_path_substs_for_ty(rscope,
-                                             span,
-                                             param_mode,
-                                             &generics,
-                                             item_segment);
-
-    // FIXME(#12938): This is a hack until we have full support for DST.
-    if Some(did) == self.tcx().lang_items.owned_box() {
-        assert_eq!(substs.types.len(TypeSpace), 1);
-        return self.tcx().mk_box(*substs.types.get(TypeSpace, 0));
-    }
-
-    decl_ty.subst(self.tcx(), &substs)
-}
-
-fn ast_ty_to_trait_ref(&self,
-                       rscope: &RegionScope,
-                       ty: &hir::Ty,
-                       bounds: &[hir::TyParamBound])
-                       -> Result<TraitAndProjections<'tcx>, ErrorReported>
-{
-    /*!
-     * In a type like `Foo + Send`, we want to wait to collect the
-     * full set of bounds before we make the object type, because we
-     * need them to infer a region bound.  (For example, if we tried
-     * made a type from just `Foo`, then it wouldn't be enough to
-     * infer a 'static bound, and hence the user would get an error.)
-     * So this function is used when we're dealing with a sum type to
-     * convert the LHS. It only accepts a type that refers to a trait
-     * name, and reports an error otherwise.
-     */
-
-    match ty.node {
-        hir::TyPath(None, ref path) => {
-            let def = match self.tcx().def_map.borrow().get(&ty.id) {
-                Some(&def::PathResolution { base_def, depth: 0, .. }) => Some(base_def),
-                _ => None
-            };
-            match def {
-                Some(Def::Trait(trait_def_id)) => {
-                    let mut projection_bounds = Vec::new();
-                    let trait_ref =
-                        self.object_path_to_poly_trait_ref(rscope,
-                                                           path.span,
-                                                           PathParamMode::Explicit,
-                                                           trait_def_id,
-                                                           path.segments.last().unwrap(),
-                                                           &mut projection_bounds);
-                    Ok((trait_ref, projection_bounds))
-                }
-                _ => {
-                    span_err!(self.tcx().sess, ty.span, E0172, "expected a reference to a trait");
-                    Err(ErrorReported)
-                }
-            }
-        }
-        _ => {
-            let mut err = struct_span_err!(self.tcx().sess, ty.span, E0178,
-                                           "expected a path on the left-hand side of `+`, not `{}`",
-                                           pprust::ty_to_string(ty));
-            let hi = bounds.iter().map(|x| match *x {
-                hir::TraitTyParamBound(ref tr, _) => tr.span.hi,
-                hir::RegionTyParamBound(ref r) => r.span.hi,
-            }).max_by_key(|x| x.to_usize());
-            let full_span = hi.map(|hi| Span {
-                lo: ty.span.lo,
-                hi: hi,
-                expn_id: ty.span.expn_id,
-            });
-            match (&ty.node, full_span) {
-                (&hir::TyRptr(None, ref mut_ty), Some(full_span)) => {
-                    let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
-                    err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
-                                        format!("&{}({} +{})",
-                                                mutbl_str,
-                                                pprust::ty_to_string(&mut_ty.ty),
-                                                pprust::bounds_to_string(bounds)));
-                }
-                (&hir::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
-                    let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
-                    err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
-                                        format!("&{} {}({} +{})",
-                                                pprust::lifetime_to_string(lt),
-                                                mutbl_str,
-                                                pprust::ty_to_string(&mut_ty.ty),
-                                                pprust::bounds_to_string(bounds)));
-                }
-
-                _ => {
-                    help!(&mut err,
-                               "perhaps you forgot parentheses? (per RFC 438)");
-                }
-            }
-            err.emit();
-            Err(ErrorReported)
-        }
-    }
-}
-
-fn trait_ref_to_object_type(&self,
-                            rscope: &RegionScope,
-                            span: Span,
-                            trait_ref: ty::PolyTraitRef<'tcx>,
-                            projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
-                            bounds: &[hir::TyParamBound])
-                            -> Ty<'tcx>
-{
-    let existential_bounds = self.conv_existential_bounds(rscope,
-                                                          span,
-                                                          trait_ref.clone(),
-                                                          projection_bounds,
-                                                          bounds);
-
-    let result = self.make_object_type(span, trait_ref, existential_bounds);
-    debug!("trait_ref_to_object_type: result={:?}",
-           result);
-
-    result
-}
-
-fn make_object_type(&self,
-                    span: Span,
-                    principal: ty::PolyTraitRef<'tcx>,
-                    bounds: ty::ExistentialBounds<'tcx>)
-                    -> Ty<'tcx> {
-    let tcx = self.tcx();
-    let object = ty::TraitTy {
-        principal: principal,
-        bounds: bounds
-    };
-    let object_trait_ref =
-        object.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
-
-    // ensure the super predicates and stop if we encountered an error
-    if self.ensure_super_predicates(span, principal.def_id()).is_err() {
-        return tcx.types.err;
-    }
-
-    // check that there are no gross object safety violations,
-    // most importantly, that the supertraits don't contain Self,
-    // to avoid ICE-s.
-    let object_safety_violations =
-        tcx.astconv_object_safety_violations(principal.def_id());
-    if !object_safety_violations.is_empty() {
-        tcx.report_object_safety_error(
-            span, principal.def_id(), None, object_safety_violations)
-            .unwrap().emit();
-        return tcx.types.err;
-    }
-
-    let mut associated_types: FnvHashSet<(DefId, ast::Name)> =
-        traits::supertraits(tcx, object_trait_ref)
-        .flat_map(|tr| {
-            let trait_def = tcx.lookup_trait_def(tr.def_id());
-            trait_def.associated_type_names
-                .clone()
-                .into_iter()
-                .map(move |associated_type_name| (tr.def_id(), associated_type_name))
-        })
-        .collect();
-
-    for projection_bound in &object.bounds.projection_bounds {
-        let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
-                    projection_bound.0.projection_ty.item_name);
-        associated_types.remove(&pair);
-    }
-
-    for (trait_def_id, name) in associated_types {
-        span_err!(tcx.sess, span, E0191,
-            "the value of the associated type `{}` (from the trait `{}`) must be specified",
-                    name,
-                    tcx.item_path_str(trait_def_id));
-    }
-
-    tcx.mk_trait(object.principal, object.bounds)
-}
-
-fn report_ambiguous_associated_type(&self,
-                                    span: Span,
-                                    type_str: &str,
-                                    trait_str: &str,
-                                    name: &str) {
-    span_err!(self.tcx().sess, span, E0223,
-              "ambiguous associated type; specify the type using the syntax \
-               `<{} as {}>::{}`",
-              type_str, trait_str, name);
-}
-
-// Search for a bound on a type parameter which includes the associated item
-// given by assoc_name. ty_param_node_id is the node id for the type parameter
-// (which might be `Self`, but only if it is the `Self` of a trait, not an
-// impl). This function will fail if there are no suitable bounds or there is
-// any ambiguity.
-fn find_bound_for_assoc_item(&self,
-                             ty_param_node_id: ast::NodeId,
-                             ty_param_name: ast::Name,
-                             assoc_name: ast::Name,
-                             span: Span)
-                             -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
-{
-    let tcx = self.tcx();
-
-    let bounds = match self.get_type_parameter_bounds(span, ty_param_node_id) {
-        Ok(v) => v,
-        Err(ErrorReported) => {
-            return Err(ErrorReported);
-        }
-    };
-
-    // Ensure the super predicates and stop if we encountered an error.
-    if bounds.iter().any(|b| self.ensure_super_predicates(span, b.def_id()).is_err()) {
-        return Err(ErrorReported);
-    }
-
-    // Check that there is exactly one way to find an associated type with the
-    // correct name.
-    let suitable_bounds: Vec<_> =
-        traits::transitive_bounds(tcx, &bounds)
-        .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name))
-        .collect();
-
-    self.one_bound_for_assoc_type(suitable_bounds,
-                                  &ty_param_name.as_str(),
-                                  &assoc_name.as_str(),
-                                  span)
-}
-
-
-// Checks that bounds contains exactly one element and reports appropriate
-// errors otherwise.
-fn one_bound_for_assoc_type(&self,
-                            bounds: Vec<ty::PolyTraitRef<'tcx>>,
-                            ty_param_name: &str,
-                            assoc_name: &str,
-                            span: Span)
-    -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
-{
-    if bounds.is_empty() {
-        span_err!(self.tcx().sess, span, E0220,
-                  "associated type `{}` not found for `{}`",
-                  assoc_name,
-                  ty_param_name);
-        return Err(ErrorReported);
-    }
-
-    if bounds.len() > 1 {
-        let mut err = struct_span_err!(self.tcx().sess, span, E0221,
-                                       "ambiguous associated type `{}` in bounds of `{}`",
-                                       assoc_name,
-                                       ty_param_name);
-
-        for bound in &bounds {
-            span_note!(&mut err, span,
-                       "associated type `{}` could derive from `{}`",
-                       ty_param_name,
-                       bound);
-        }
-        err.emit();
-    }
-
-    Ok(bounds[0].clone())
-}
-
-// Create a type from a path to an associated type.
-// For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C
-// and item_segment is the path segment for D. We return a type and a def for
-// the whole path.
-// Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type
-// parameter or Self.
-fn associated_path_def_to_ty(&self,
-                             span: Span,
-                             ty: Ty<'tcx>,
-                             ty_path_def: Def,
-                             item_segment: &hir::PathSegment)
-                             -> (Ty<'tcx>, Def)
-{
-    let tcx = self.tcx();
-    let assoc_name = item_segment.identifier.name;
-
-    debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
-
-    tcx.prohibit_type_params(slice::ref_slice(item_segment));
-
-    // Find the type of the associated item, and the trait where the associated
-    // item is declared.
-    let bound = match (&ty.sty, ty_path_def) {
-        (_, Def::SelfTy(Some(trait_did), Some(impl_id))) => {
-            // `Self` in an impl of a trait - we have a concrete self type and a
-            // trait reference.
-            let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap();
-            let trait_ref = if let Some(free_substs) = self.get_free_substs() {
-                trait_ref.subst(tcx, free_substs)
-            } else {
-                trait_ref
-            };
-
-            if self.ensure_super_predicates(span, trait_did).is_err() {
-                return (tcx.types.err, ty_path_def);
-            }
-
-            let candidates: Vec<ty::PolyTraitRef> =
-                traits::supertraits(tcx, ty::Binder(trait_ref))
-                .filter(|r| self.trait_defines_associated_type_named(r.def_id(),
-                                                                     assoc_name))
-                .collect();
-
-            match self.one_bound_for_assoc_type(candidates,
-                                                "Self",
-                                                &assoc_name.as_str(),
-                                                span) {
-                Ok(bound) => bound,
-                Err(ErrorReported) => return (tcx.types.err, ty_path_def),
-            }
-        }
-        (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
-            let trait_node_id = tcx.map.as_local_node_id(trait_did).unwrap();
-            match self.find_bound_for_assoc_item(trait_node_id,
-                                                 keywords::SelfType.name(),
-                                                 assoc_name,
-                                                 span) {
-                Ok(bound) => bound,
-                Err(ErrorReported) => return (tcx.types.err, ty_path_def),
-            }
-        }
-        (&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => {
-            let param_node_id = tcx.map.as_local_node_id(param_did).unwrap();
-            match self.find_bound_for_assoc_item(param_node_id,
-                                                 param_name,
-                                                 assoc_name,
-                                                 span) {
-                Ok(bound) => bound,
-                Err(ErrorReported) => return (tcx.types.err, ty_path_def),
-            }
-        }
-        _ => {
-            self.report_ambiguous_associated_type(span,
-                                                  &ty.to_string(),
-                                                  "Trait",
-                                                  &assoc_name.as_str());
-            return (tcx.types.err, ty_path_def);
-        }
-    };
-
-    let trait_did = bound.0.def_id;
-    let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
-
-    let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) {
-        // `ty::trait_items` used below requires information generated
-        // by type collection, which may be in progress at this point.
-        match tcx.map.expect_item(trait_id).node {
-            hir::ItemTrait(_, _, _, ref trait_items) => {
-                let item = trait_items.iter()
-                                      .find(|i| i.name == assoc_name)
-                                      .expect("missing associated type");
-                tcx.map.local_def_id(item.id)
-            }
-            _ => bug!()
-        }
-    } else {
-        let trait_items = tcx.trait_items(trait_did);
-        let item = trait_items.iter().find(|i| i.name() == assoc_name);
-        item.expect("missing associated type").def_id()
-    };
-
-    (ty, Def::AssociatedTy(trait_did, item_did))
-}
-
-fn qpath_to_ty(&self,
-               rscope: &RegionScope,
-               span: Span,
-               param_mode: PathParamMode,
-               opt_self_ty: Option<Ty<'tcx>>,
-               trait_def_id: DefId,
-               trait_segment: &hir::PathSegment,
-               item_segment: &hir::PathSegment)
-               -> Ty<'tcx>
-{
-    let tcx = self.tcx();
-
-    tcx.prohibit_type_params(slice::ref_slice(item_segment));
-
-    let self_ty = if let Some(ty) = opt_self_ty {
-        ty
-    } else {
-        let path_str = tcx.item_path_str(trait_def_id);
-        self.report_ambiguous_associated_type(span,
-                                              "Type",
-                                              &path_str,
-                                              &item_segment.identifier.name.as_str());
-        return tcx.types.err;
-    };
-
-    debug!("qpath_to_ty: self_type={:?}", self_ty);
-
-    let trait_ref = self.ast_path_to_mono_trait_ref(rscope,
-                                                    span,
-                                                    param_mode,
-                                                    trait_def_id,
-                                                    Some(self_ty),
-                                                    trait_segment);
-
-    debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
-
-    self.projected_ty(span, trait_ref, item_segment.identifier.name)
-}
-
-/// Convert a type supplied as value for a type argument from AST into our
-/// our internal representation. This is the same as `ast_ty_to_ty` but that
-/// it applies the object lifetime default.
-///
-/// # Parameters
-///
-/// * `this`, `rscope`: the surrounding context
-/// * `decl_generics`: the generics of the struct/enum/trait declaration being
-///   referenced
-/// * `index`: the index of the type parameter being instantiated from the list
-///   (we assume it is in the `TypeSpace`)
-/// * `region_substs`: a partial substitution consisting of
-///   only the region type parameters being supplied to this type.
-/// * `ast_ty`: the ast representation of the type being supplied
-pub fn ast_ty_arg_to_ty(&self,
-                        rscope: &RegionScope,
-                        decl_generics: &ty::Generics<'tcx>,
-                        index: usize,
-                        region_substs: &Substs<'tcx>,
-                        ast_ty: &hir::Ty)
-                        -> Ty<'tcx>
-{
-    let tcx = self.tcx();
-
-    if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) {
-        let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs);
-        let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default);
-        self.ast_ty_to_ty(rscope1, ast_ty)
-    } else {
-        self.ast_ty_to_ty(rscope, ast_ty)
-    }
-}
-
-// Check the base def in a PathResolution and convert it to a Ty. If there are
-// associated types in the PathResolution, these will need to be separately
-// resolved.
-fn base_def_to_ty(&self,
-                  rscope: &RegionScope,
-                  span: Span,
-                  param_mode: PathParamMode,
-                  def: &Def,
-                  opt_self_ty: Option<Ty<'tcx>>,
-                  base_segments: &[hir::PathSegment])
-                  -> Ty<'tcx> {
-    let tcx = self.tcx();
-
-    match *def {
-        Def::Trait(trait_def_id) => {
-            // N.B. this case overlaps somewhat with
-            // TyObjectSum, see that fn for details
-            let mut projection_bounds = Vec::new();
-
-            let trait_ref =
-                self.object_path_to_poly_trait_ref(rscope,
-                                                   span,
-                                                   param_mode,
-                                                   trait_def_id,
-                                                   base_segments.last().unwrap(),
-                                                   &mut projection_bounds);
-
-            tcx.prohibit_type_params(base_segments.split_last().unwrap().1);
-            self.trait_ref_to_object_type(rscope,
-                                          span,
-                                          trait_ref,
-                                          projection_bounds,
-                                          &[])
-        }
-        Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
-            tcx.prohibit_type_params(base_segments.split_last().unwrap().1);
-            self.ast_path_to_ty(rscope,
-                                span,
-                                param_mode,
-                                did,
-                                base_segments.last().unwrap())
-        }
-        Def::TyParam(space, index, _, name) => {
-            tcx.prohibit_type_params(base_segments);
-            tcx.mk_param(space, index, name)
-        }
-        Def::SelfTy(_, Some(impl_id)) => {
-            // Self in impl (we know the concrete type).
-            tcx.prohibit_type_params(base_segments);
-            let ty = tcx.node_id_to_type(impl_id);
-            if let Some(free_substs) = self.get_free_substs() {
-                ty.subst(tcx, free_substs)
-            } else {
-                ty
-            }
-        }
-        Def::SelfTy(Some(_), None) => {
-            // Self in trait.
-            tcx.prohibit_type_params(base_segments);
-            tcx.mk_self_type()
-        }
-        Def::AssociatedTy(trait_did, _) => {
-            tcx.prohibit_type_params(&base_segments[..base_segments.len()-2]);
-            self.qpath_to_ty(rscope,
-                             span,
-                             param_mode,
-                             opt_self_ty,
-                             trait_did,
-                             &base_segments[base_segments.len()-2],
-                             base_segments.last().unwrap())
-        }
-        Def::Mod(..) => {
-            // Used as sentinel by callers to indicate the `<T>::A::B::C` form.
-            // FIXME(#22519) This part of the resolution logic should be
-            // avoided entirely for that form, once we stop needed a Def
-            // for `associated_path_def_to_ty`.
-            // Fixing this will also let use resolve <Self>::Foo the same way we
-            // resolve Self::Foo, at the moment we can't resolve the former because
-            // we don't have the trait information around, which is just sad.
-
-            assert!(base_segments.is_empty());
-
-            opt_self_ty.expect("missing T in <T>::a::b::c")
-        }
-        Def::PrimTy(prim_ty) => {
-            tcx.prim_ty_to_ty(base_segments, prim_ty)
-        }
-        Def::Err => {
-            self.set_tainted_by_errors();
-            return self.tcx().types.err;
-        }
-        _ => {
-            span_err!(tcx.sess, span, E0248,
-                      "found value `{}` used as a type",
-                      tcx.item_path_str(def.def_id()));
-            return self.tcx().types.err;
-        }
-    }
-}
-
-// Note that both base_segments and assoc_segments may be empty, although not at
-// the same time.
-pub fn finish_resolving_def_to_ty(&self,
-                                  rscope: &RegionScope,
-                                  span: Span,
-                                  param_mode: PathParamMode,
-                                  def: &Def,
-                                  opt_self_ty: Option<Ty<'tcx>>,
-                                  base_segments: &[hir::PathSegment],
-                                  assoc_segments: &[hir::PathSegment])
-                                  -> Ty<'tcx> {
-    let mut ty = self.base_def_to_ty(rscope,
-                                     span,
-                                     param_mode,
-                                     def,
-                                     opt_self_ty,
-                                     base_segments);
-    let mut def = *def;
-    // If any associated type segments remain, attempt to resolve them.
-    for segment in assoc_segments {
-        if ty.sty == ty::TyError {
-            break;
-        }
-        // This is pretty bad (it will fail except for T::A and Self::A).
-        let (a_ty, a_def) = self.associated_path_def_to_ty(span,
-                                                           ty,
-                                                           def,
-                                                           segment);
-        ty = a_ty;
-        def = a_def;
-    }
-    ty
-}
-
-/// Parses the programmer's textual representation of a type into our
-/// internal notion of a type.
-pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
-    debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})",
-           ast_ty.id, ast_ty);
-
-    let tcx = self.tcx();
-
-    match ast_ty.node {
-        hir::TyVec(ref ty) => {
-            tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty))
-        }
-        hir::TyObjectSum(ref ty, ref bounds) => {
-            match self.ast_ty_to_trait_ref(rscope, &ty, bounds) {
-                Ok((trait_ref, projection_bounds)) => {
-                    self.trait_ref_to_object_type(rscope,
-                                                  ast_ty.span,
-                                                  trait_ref,
-                                                  projection_bounds,
-                                                  bounds)
-                }
-                Err(ErrorReported) => {
-                    self.tcx().types.err
-                }
-            }
-        }
-        hir::TyPtr(ref mt) => {
-            tcx.mk_ptr(ty::TypeAndMut {
-                ty: self.ast_ty_to_ty(rscope, &mt.ty),
-                mutbl: mt.mutbl
-            })
-        }
-        hir::TyRptr(ref region, ref mt) => {
-            let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region);
-            debug!("TyRef r={:?}", r);
-            let rscope1 =
-                &ObjectLifetimeDefaultRscope::new(
-                    rscope,
-                    ty::ObjectLifetimeDefault::Specific(r));
-            let t = self.ast_ty_to_ty(rscope1, &mt.ty);
-            tcx.mk_ref(tcx.mk_region(r), ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
-        }
-        hir::TyTup(ref fields) => {
-            let flds = fields.iter()
-                             .map(|t| self.ast_ty_to_ty(rscope, &t))
-                             .collect();
-            tcx.mk_tup(flds)
-        }
-        hir::TyBareFn(ref bf) => {
-            require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
-            tcx.mk_fn_ptr(self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl))
-        }
-        hir::TyPolyTraitRef(ref bounds) => {
-            self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds)
-        }
-        hir::TyPath(ref maybe_qself, ref path) => {
-            let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) {
-                d
-            } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
-                // Create some fake resolution that can't possibly be a type.
-                def::PathResolution {
-                    base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
-                    depth: path.segments.len()
-                }
-            } else {
-                span_bug!(ast_ty.span, "unbound path {:?}", ast_ty)
-            };
-            let def = path_res.base_def;
-            let base_ty_end = path.segments.len() - path_res.depth;
-            let opt_self_ty = maybe_qself.as_ref().map(|qself| {
-                self.ast_ty_to_ty(rscope, &qself.ty)
-            });
-            let ty = self.finish_resolving_def_to_ty(rscope,
-                                                     ast_ty.span,
-                                                     PathParamMode::Explicit,
-                                                     &def,
-                                                     opt_self_ty,
-                                                     &path.segments[..base_ty_end],
-                                                     &path.segments[base_ty_end..]);
-
-            if path_res.depth != 0 && ty.sty != ty::TyError {
-                // Write back the new resolution.
-                tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution {
-                    base_def: def,
-                    depth: 0
-                });
-            }
-
-            ty
-        }
-        hir::TyFixedLengthVec(ref ty, ref e) => {
-            let hint = UncheckedExprHint(tcx.types.usize);
-            match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) {
-                Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
-                    let i = i.as_u64(tcx.sess.target.uint_type);
-                    assert_eq!(i as usize as u64, i);
-                    tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize)
-                },
-                Ok(val) => {
-                    span_err!(tcx.sess, ast_ty.span, E0249,
-                              "expected usize value for array length, got {}", val.description());
-                    self.tcx().types.err
-                },
-                // array length errors happen before the global constant check
-                // so we need to report the real error
-                Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) |
-                Err(r) => {
-                    let mut err = struct_span_err!(tcx.sess, r.span, E0250,
-                                                   "array length constant evaluation error: {}",
-                                                   r.description());
-                    if !ast_ty.span.contains(r.span) {
-                        span_note!(&mut err, ast_ty.span, "for array length here")
+            None => match rscope.anon_regions(default_span, 1) {
+                Ok(rs) => rs[0],
+                Err(params) => {
+                    let mut err = struct_span_err!(self.tcx().sess, default_span, E0106,
+                                                   "missing lifetime specifier");
+                    if let Some(params) = params {
+                        report_elision_failure(&mut err, params);
                     }
                     err.emit();
-                    self.tcx().types.err
-                }
-            }
-        }
-        hir::TyTypeof(ref _e) => {
-            span_err!(tcx.sess, ast_ty.span, E0516,
-                  "`typeof` is a reserved keyword but unimplemented");
-            tcx.types.err
-        }
-        hir::TyInfer => {
-            // TyInfer also appears as the type of arguments or return
-            // values in a ExprClosure, or as
-            // the type of local variables. Both of these cases are
-            // handled specially and will not descend into this routine.
-            self.ty_infer(None, None, None, ast_ty.span)
-        }
-    }
-}
-
-pub fn ty_of_arg(&self,
-                 rscope: &RegionScope,
-                 a: &hir::Arg,
-                 expected_ty: Option<Ty<'tcx>>)
-                 -> Ty<'tcx>
-{
-    match a.ty.node {
-        hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
-        hir::TyInfer => self.ty_infer(None, None, None, a.ty.span),
-        _ => self.ast_ty_to_ty(rscope, &a.ty),
-    }
-}
-
-pub fn ty_of_method(&self,
-                    sig: &hir::MethodSig,
-                    untransformed_self_ty: Ty<'tcx>)
-                    -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
-    let self_info = Some(SelfInfo {
-        untransformed_self_ty: untransformed_self_ty,
-        explicit_self: &sig.explicit_self,
-    });
-    let (bare_fn_ty, optional_explicit_self_category) =
-        self.ty_of_method_or_bare_fn(sig.unsafety,
-                                     sig.abi,
-                                     self_info,
-                                     &sig.decl);
-    (bare_fn_ty, optional_explicit_self_category.unwrap())
-}
-
-pub fn ty_of_bare_fn(&self,
-                     unsafety: hir::Unsafety, abi: abi::Abi,
-                     decl: &hir::FnDecl)
-                     -> &'tcx ty::BareFnTy<'tcx> {
-    let (bare_fn_ty, _) = self.ty_of_method_or_bare_fn(unsafety, abi, None, decl);
-    bare_fn_ty
-}
-
-fn ty_of_method_or_bare_fn<'a>(&self,
-                               unsafety: hir::Unsafety,
-                               abi: abi::Abi,
-                               opt_self_info: Option<SelfInfo<'a, 'tcx>>,
-                               decl: &hir::FnDecl)
-                               -> (&'tcx ty::BareFnTy<'tcx>,
-                                   Option<ty::ExplicitSelfCategory>)
-{
-    debug!("ty_of_method_or_bare_fn");
-
-    // New region names that appear inside of the arguments of the function
-    // declaration are bound to that function type.
-    let rb = rscope::BindingRscope::new();
-
-    // `implied_output_region` is the region that will be assumed for any
-    // region parameters in the return type. In accordance with the rules for
-    // lifetime elision, we can determine it in two ways. First (determined
-    // here), if self is by-reference, then the implied output region is the
-    // region of the self parameter.
-    let (self_ty, explicit_self_category) = match opt_self_info {
-        None => (None, None),
-        Some(self_info) => self.determine_self_type(&rb, self_info)
-    };
-
-    // HACK(eddyb) replace the fake self type in the AST with the actual type.
-    let arg_params = if self_ty.is_some() {
-        &decl.inputs[1..]
-    } else {
-        &decl.inputs[..]
-    };
-    let arg_tys: Vec<Ty> =
-        arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
-    let arg_pats: Vec<String> =
-        arg_params.iter().map(|a| pprust::pat_to_string(&a.pat)).collect();
-
-    // Second, if there was exactly one lifetime (either a substitution or a
-    // reference) in the arguments, then any anonymous regions in the output
-    // have that lifetime.
-    let implied_output_region = match explicit_self_category {
-        Some(ty::ExplicitSelfCategory::ByReference(region, _)) => Ok(region),
-        _ => self.find_implied_output_region(&arg_tys, arg_pats)
-    };
-
-    let output_ty = match decl.output {
-        hir::Return(ref output) =>
-            ty::FnConverging(self.convert_ty_with_lifetime_elision(implied_output_region,
-                                                                   &output)),
-        hir::DefaultReturn(..) => ty::FnConverging(self.tcx().mk_nil()),
-        hir::NoReturn(..) => ty::FnDiverging
-    };
-
-    (self.tcx().mk_bare_fn(ty::BareFnTy {
-        unsafety: unsafety,
-        abi: abi,
-        sig: ty::Binder(ty::FnSig {
-            inputs: self_ty.into_iter().chain(arg_tys).collect(),
-            output: output_ty,
-            variadic: decl.variadic
-        }),
-    }), explicit_self_category)
-}
-
-fn determine_self_type<'a>(&self,
-                           rscope: &RegionScope,
-                           self_info: SelfInfo<'a, 'tcx>)
-                           -> (Option<Ty<'tcx>>, Option<ty::ExplicitSelfCategory>)
-{
-    let self_ty = self_info.untransformed_self_ty;
-    return match self_info.explicit_self.node {
-        hir::SelfStatic => (None, Some(ty::ExplicitSelfCategory::Static)),
-        hir::SelfValue(_) => {
-            (Some(self_ty), Some(ty::ExplicitSelfCategory::ByValue))
-        }
-        hir::SelfRegion(ref lifetime, mutability, _) => {
-            let region =
-                self.opt_ast_region_to_region(rscope,
-                                              self_info.explicit_self.span,
-                                              lifetime);
-            (Some(self.tcx().mk_ref(
-                self.tcx().mk_region(region),
-                ty::TypeAndMut {
-                    ty: self_ty,
-                    mutbl: mutability
-                })),
-             Some(ty::ExplicitSelfCategory::ByReference(region, mutability)))
-        }
-        hir::SelfExplicit(ref ast_type, _) => {
-            let explicit_type = self.ast_ty_to_ty(rscope, &ast_type);
-
-            // We wish to (for now) categorize an explicit self
-            // declaration like `self: SomeType` into either `self`,
-            // `&self`, `&mut self`, or `Box<self>`. We do this here
-            // by some simple pattern matching. A more precise check
-            // is done later in `check_method_self_type()`.
-            //
-            // Examples:
-            //
-            // ```
-            // impl Foo for &T {
-            //     // Legal declarations:
-            //     fn method1(self: &&T); // ExplicitSelfCategory::ByReference
-            //     fn method2(self: &T); // ExplicitSelfCategory::ByValue
-            //     fn method3(self: Box<&T>); // ExplicitSelfCategory::ByBox
-            //
-            //     // Invalid cases will be caught later by `check_method_self_type`:
-            //     fn method_err1(self: &mut T); // ExplicitSelfCategory::ByReference
-            // }
-            // ```
-            //
-            // To do the check we just count the number of "modifiers"
-            // on each type and compare them. If they are the same or
-            // the impl has more, we call it "by value". Otherwise, we
-            // look at the outermost modifier on the method decl and
-            // call it by-ref, by-box as appropriate. For method1, for
-            // example, the impl type has one modifier, but the method
-            // type has two, so we end up with
-            // ExplicitSelfCategory::ByReference.
-
-            let impl_modifiers = count_modifiers(self_info.untransformed_self_ty);
-            let method_modifiers = count_modifiers(explicit_type);
-
-            debug!("determine_explicit_self_category(self_info.untransformed_self_ty={:?} \
-                   explicit_type={:?} \
-                   modifiers=({},{})",
-                   self_info.untransformed_self_ty,
-                   explicit_type,
-                   impl_modifiers,
-                   method_modifiers);
-
-            let category = if impl_modifiers >= method_modifiers {
-                ty::ExplicitSelfCategory::ByValue
-            } else {
-                match explicit_type.sty {
-                    ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(*r, mt.mutbl),
-                    ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox,
-                    _ => ty::ExplicitSelfCategory::ByValue,
-                }
-            };
-
-            (Some(explicit_type), Some(category))
-        }
-    };
-
-    fn count_modifiers(ty: Ty) -> usize {
-        match ty.sty {
-            ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1,
-            ty::TyBox(t) => count_modifiers(t) + 1,
-            _ => 0,
-        }
-    }
-}
-
-pub fn ty_of_closure(&self,
-    unsafety: hir::Unsafety,
-    decl: &hir::FnDecl,
-    abi: abi::Abi,
-    expected_sig: Option<ty::FnSig<'tcx>>)
-    -> ty::ClosureTy<'tcx>
-{
-    debug!("ty_of_closure(expected_sig={:?})",
-           expected_sig);
-
-    // new region names that appear inside of the fn decl are bound to
-    // that function type
-    let rb = rscope::BindingRscope::new();
-
-    let input_tys: Vec<_> = decl.inputs.iter().enumerate().map(|(i, a)| {
-        let expected_arg_ty = expected_sig.as_ref().and_then(|e| {
-            // no guarantee that the correct number of expected args
-            // were supplied
-            if i < e.inputs.len() {
-                Some(e.inputs[i])
-            } else {
-                None
-            }
-        });
-        self.ty_of_arg(&rb, a, expected_arg_ty)
-    }).collect();
-
-    let expected_ret_ty = expected_sig.map(|e| e.output);
-
-    let is_infer = match decl.output {
-        hir::Return(ref output) if output.node == hir::TyInfer => true,
-        hir::DefaultReturn(..) => true,
-        _ => false
-    };
-
-    let output_ty = match decl.output {
-        _ if is_infer && expected_ret_ty.is_some() =>
-            expected_ret_ty.unwrap(),
-        _ if is_infer =>
-            ty::FnConverging(self.ty_infer(None, None, None, decl.output.span())),
-        hir::Return(ref output) =>
-            ty::FnConverging(self.ast_ty_to_ty(&rb, &output)),
-        hir::DefaultReturn(..) => bug!(),
-        hir::NoReturn(..) => ty::FnDiverging
-    };
-
-    debug!("ty_of_closure: input_tys={:?}", input_tys);
-    debug!("ty_of_closure: output_ty={:?}", output_ty);
-
-    ty::ClosureTy {
-        unsafety: unsafety,
-        abi: abi,
-        sig: ty::Binder(ty::FnSig {inputs: input_tys,
-                                   output: output_ty,
-                                   variadic: decl.variadic}),
-    }
-}
-
-/// Given an existential type like `Foo+'a+Bar`, this routine converts the `'a` and `Bar` intos an
-/// `ExistentialBounds` struct. The `main_trait_refs` argument specifies the `Foo` -- it is absent
-/// for closures. Eventually this should all be normalized, I think, so that there is no "main
-/// trait ref" and instead we just have a flat list of bounds as the existential type.
-fn conv_existential_bounds(&self,
-    rscope: &RegionScope,
-    span: Span,
-    principal_trait_ref: ty::PolyTraitRef<'tcx>,
-    projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
-    ast_bounds: &[hir::TyParamBound])
-    -> ty::ExistentialBounds<'tcx>
-{
-    let partitioned_bounds =
-        partition_bounds(self.tcx(), span, ast_bounds);
-
-    self.conv_existential_bounds_from_partitioned_bounds(
-        rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds)
-}
-
-fn conv_ty_poly_trait_ref(&self,
-    rscope: &RegionScope,
-    span: Span,
-    ast_bounds: &[hir::TyParamBound])
-    -> Ty<'tcx>
-{
-    let mut partitioned_bounds = partition_bounds(self.tcx(), span, &ast_bounds[..]);
-
-    let mut projection_bounds = Vec::new();
-    let main_trait_bound = if !partitioned_bounds.trait_bounds.is_empty() {
-        let trait_bound = partitioned_bounds.trait_bounds.remove(0);
-        self.instantiate_poly_trait_ref(rscope,
-                                        trait_bound,
-                                        None,
-                                        &mut projection_bounds)
-    } else {
-        span_err!(self.tcx().sess, span, E0224,
-                  "at least one non-builtin trait is required for an object type");
-        return self.tcx().types.err;
-    };
-
-    let bounds =
-        self.conv_existential_bounds_from_partitioned_bounds(rscope,
-                                                             span,
-                                                             main_trait_bound.clone(),
-                                                             projection_bounds,
-                                                             partitioned_bounds);
-
-    self.make_object_type(span, main_trait_bound, bounds)
-}
-
-pub fn conv_existential_bounds_from_partitioned_bounds(&self,
-    rscope: &RegionScope,
-    span: Span,
-    principal_trait_ref: ty::PolyTraitRef<'tcx>,
-    projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, // Empty for boxed closures
-    partitioned_bounds: PartitionedBounds)
-    -> ty::ExistentialBounds<'tcx>
-{
-    let PartitionedBounds { builtin_bounds,
-                            trait_bounds,
-                            region_bounds } =
-        partitioned_bounds;
-
-    if !trait_bounds.is_empty() {
-        let b = &trait_bounds[0];
-        span_err!(self.tcx().sess, b.trait_ref.path.span, E0225,
-                  "only the builtin traits can be used as closure or object bounds");
-    }
-
-    let region_bound =
-        self.compute_object_lifetime_bound(span,
-                                           &region_bounds,
-                                           principal_trait_ref,
-                                           builtin_bounds);
-
-    let region_bound = match region_bound {
-        Some(r) => r,
-        None => {
-            match rscope.object_lifetime_default(span) {
-                Some(r) => r,
-                None => {
-                    span_err!(self.tcx().sess, span, E0228,
-                              "the lifetime bound for this object type cannot be deduced \
-                               from context; please supply an explicit bound");
                     ty::ReStatic
                 }
             }
+        };
+
+        debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}",
+                opt_lifetime,
+                r);
+
+        r
+    }
+
+    /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
+    /// returns an appropriate set of substitutions for this particular reference to `I`.
+    pub fn ast_path_substs_for_ty(&self,
+        rscope: &RegionScope,
+        span: Span,
+        param_mode: PathParamMode,
+        decl_generics: &ty::Generics<'tcx>,
+        item_segment: &hir::PathSegment)
+        -> Substs<'tcx>
+    {
+        let tcx = self.tcx();
+
+        // ast_path_substs() is only called to convert paths that are
+        // known to refer to traits, types, or structs. In these cases,
+        // all type parameters defined for the item being referenced will
+        // be in the TypeSpace or SelfSpace.
+        //
+        // Note: in the case of traits, the self parameter is also
+        // defined, but we don't currently create a `type_param_def` for
+        // `Self` because it is implicit.
+        assert!(decl_generics.regions.all(|d| d.space == TypeSpace));
+        assert!(decl_generics.types.all(|d| d.space != FnSpace));
+
+        let (regions, types, assoc_bindings) = match item_segment.parameters {
+            hir::AngleBracketedParameters(ref data) => {
+                self.convert_angle_bracketed_parameters(rscope, span, decl_generics, data)
+            }
+            hir::ParenthesizedParameters(..) => {
+                span_err!(tcx.sess, span, E0214,
+                          "parenthesized parameters may only be used with a trait");
+                let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
+                (Substs::empty(),
+                 ty_param_defs.iter().map(|_| tcx.types.err).collect(),
+                 vec![])
+            }
+        };
+
+        assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
+
+        self.create_substs_for_ast_path(span,
+                                        param_mode,
+                                        decl_generics,
+                                        None,
+                                        types,
+                                        regions)
+    }
+
+    fn create_region_substs(&self,
+        rscope: &RegionScope,
+        span: Span,
+        decl_generics: &ty::Generics<'tcx>,
+        regions_provided: Vec<ty::Region>)
+        -> Substs<'tcx>
+    {
+        let tcx = self.tcx();
+
+        // If the type is parameterized by this region, then replace this
+        // region with the current anon region binding (in other words,
+        // whatever & would get replaced with).
+        let expected_num_region_params = decl_generics.regions.len(TypeSpace);
+        let supplied_num_region_params = regions_provided.len();
+        let regions = if expected_num_region_params == supplied_num_region_params {
+            regions_provided
+        } else {
+            let anon_regions =
+                rscope.anon_regions(span, expected_num_region_params);
+
+            if supplied_num_region_params != 0 || anon_regions.is_err() {
+                report_lifetime_number_error(tcx, span,
+                                             supplied_num_region_params,
+                                             expected_num_region_params);
+            }
+
+            match anon_regions {
+                Ok(anon_regions) => anon_regions,
+                Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect()
+            }
+        };
+        Substs::new_type(vec![], regions)
+    }
+
+    /// Given the type/region arguments provided to some path (along with
+    /// an implicit Self, if this is a trait reference) returns the complete
+    /// set of substitutions. This may involve applying defaulted type parameters.
+    ///
+    /// Note that the type listing given here is *exactly* what the user provided.
+    ///
+    /// The `region_substs` should be the result of `create_region_substs`
+    /// -- that is, a substitution with no types but the correct number of
+    /// regions.
+    fn create_substs_for_ast_path(&self,
+        span: Span,
+        param_mode: PathParamMode,
+        decl_generics: &ty::Generics<'tcx>,
+        self_ty: Option<Ty<'tcx>>,
+        types_provided: Vec<Ty<'tcx>>,
+        region_substs: Substs<'tcx>)
+        -> Substs<'tcx>
+    {
+        let tcx = self.tcx();
+
+        debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \
+               types_provided={:?}, region_substs={:?})",
+               decl_generics, self_ty, types_provided,
+               region_substs);
+
+        assert_eq!(region_substs.regions.len(TypeSpace), decl_generics.regions.len(TypeSpace));
+        assert!(region_substs.types.is_empty());
+
+        // Convert the type parameters supplied by the user.
+        let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
+        let formal_ty_param_count = ty_param_defs.len();
+        let required_ty_param_count = ty_param_defs.iter()
+                                                   .take_while(|x| x.default.is_none())
+                                                   .count();
+
+        let mut type_substs = self.get_type_substs_for_defs(span,
+                                                            types_provided,
+                                                            param_mode,
+                                                            ty_param_defs,
+                                                            region_substs.clone(),
+                                                            self_ty);
+
+        let supplied_ty_param_count = type_substs.len();
+        check_type_argument_count(self.tcx(), span, supplied_ty_param_count,
+                                  required_ty_param_count, formal_ty_param_count);
+
+        if supplied_ty_param_count < required_ty_param_count {
+            while type_substs.len() < required_ty_param_count {
+                type_substs.push(tcx.types.err);
+            }
+        } else if supplied_ty_param_count > formal_ty_param_count {
+            type_substs.truncate(formal_ty_param_count);
         }
-    };
+        assert!(type_substs.len() >= required_ty_param_count &&
+                type_substs.len() <= formal_ty_param_count);
 
-    debug!("region_bound: {:?}", region_bound);
+        let mut substs = region_substs;
+        substs.types.extend(TypeSpace, type_substs.into_iter());
 
-    ty::ExistentialBounds::new(region_bound, builtin_bounds, projection_bounds)
-}
+        match self_ty {
+            None => {
+                // If no self-type is provided, it's still possible that
+                // one was declared, because this could be an object type.
+            }
+            Some(ty) => {
+                // If a self-type is provided, one should have been
+                // "declared" (in other words, this should be a
+                // trait-ref).
+                assert!(decl_generics.types.get_self().is_some());
+                substs.types.push(SelfSpace, ty);
+            }
+        }
 
-/// Given the bounds on an object, determines what single region bound
-/// (if any) we can use to summarize this type. The basic idea is that we will use the bound the
-/// user provided, if they provided one, and otherwise search the supertypes of trait bounds for
-/// region bounds. It may be that we can derive no bound at all, in which case we return `None`.
-fn compute_object_lifetime_bound(&self,
-    span: Span,
-    explicit_region_bounds: &[&hir::Lifetime],
-    principal_trait_ref: ty::PolyTraitRef<'tcx>,
-    builtin_bounds: ty::BuiltinBounds)
-    -> Option<ty::Region> // if None, use the default
-{
-    let tcx = self.tcx();
+        let actual_supplied_ty_param_count = substs.types.len(TypeSpace);
+        for param in &ty_param_defs[actual_supplied_ty_param_count..] {
+            if let Some(default) = param.default {
+                // If we are converting an object type, then the
+                // `Self` parameter is unknown. However, some of the
+                // other type parameters may reference `Self` in their
+                // defaults. This will lead to an ICE if we are not
+                // careful!
+                if self_ty.is_none() && default.has_self_ty() {
+                    span_err!(tcx.sess, span, E0393,
+                              "the type parameter `{}` must be explicitly specified \
+                               in an object type because its default value `{}` references \
+                               the type `Self`",
+                              param.name,
+                              default);
+                    substs.types.push(TypeSpace, tcx.types.err);
+                } else {
+                    // This is a default type parameter.
+                    let default = default.subst_spanned(tcx,
+                                                        &substs,
+                                                        Some(span));
+                    substs.types.push(TypeSpace, default);
+                }
+            } else {
+                span_bug!(span, "extra parameter without default");
+            }
+        }
 
-    debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
-           principal_trait_ref={:?}, builtin_bounds={:?})",
-           explicit_region_bounds,
-           principal_trait_ref,
-           builtin_bounds);
+        debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}",
+               decl_generics, self_ty, substs);
 
-    if explicit_region_bounds.len() > 1 {
-        span_err!(tcx.sess, explicit_region_bounds[1].span, E0226,
-            "only a single explicit lifetime bound is permitted");
+        substs
     }
 
-    if !explicit_region_bounds.is_empty() {
-        // Explicitly specified region bound. Use that.
-        let r = explicit_region_bounds[0];
-        return Some(ast_region_to_region(tcx, r));
+    /// Returns types_provided if it is not empty, otherwise populating the
+    /// type parameters with inference variables as appropriate.
+    fn get_type_substs_for_defs(&self,
+                                span: Span,
+                                types_provided: Vec<Ty<'tcx>>,
+                                param_mode: PathParamMode,
+                                ty_param_defs: &[ty::TypeParameterDef<'tcx>],
+                                mut substs: Substs<'tcx>,
+                                self_ty: Option<Ty<'tcx>>)
+                                -> Vec<Ty<'tcx>>
+    {
+        fn default_type_parameter<'tcx>(p: &ty::TypeParameterDef<'tcx>, self_ty: Option<Ty<'tcx>>)
+                                        -> Option<ty::TypeParameterDef<'tcx>>
+        {
+            if let Some(ref default) = p.default {
+                if self_ty.is_none() && default.has_self_ty() {
+                    // There is no suitable inference default for a type parameter
+                    // that references self with no self-type provided.
+                    return None;
+                }
+            }
+
+            Some(p.clone())
+        }
+
+        if param_mode == PathParamMode::Optional && types_provided.is_empty() {
+            ty_param_defs
+                .iter()
+                .map(|p| self.ty_infer(default_type_parameter(p, self_ty), Some(&mut substs),
+                                       Some(TypeSpace), span))
+                .collect()
+        } else {
+            types_provided
+        }
     }
 
-    if let Err(ErrorReported) = self.ensure_super_predicates(span,principal_trait_ref.def_id()) {
-        return Some(ty::ReStatic);
+    fn convert_angle_bracketed_parameters(&self,
+                                          rscope: &RegionScope,
+                                          span: Span,
+                                          decl_generics: &ty::Generics<'tcx>,
+                                          data: &hir::AngleBracketedParameterData)
+                                          -> (Substs<'tcx>,
+                                              Vec<Ty<'tcx>>,
+                                              Vec<ConvertedBinding<'tcx>>)
+    {
+        let regions: Vec<_> =
+            data.lifetimes.iter()
+                          .map(|l| ast_region_to_region(self.tcx(), l))
+                          .collect();
+
+        let region_substs =
+            self.create_region_substs(rscope, span, decl_generics, regions);
+
+        let types: Vec<_> =
+            data.types.iter()
+                      .enumerate()
+                      .map(|(i,t)| self.ast_ty_arg_to_ty(rscope, decl_generics,
+                                                         i, &region_substs, t))
+                      .collect();
+
+        let assoc_bindings: Vec<_> =
+            data.bindings.iter()
+                         .map(|b| ConvertedBinding { item_name: b.name,
+                                                     ty: self.ast_ty_to_ty(rscope, &b.ty),
+                                                     span: b.span })
+                         .collect();
+
+        (region_substs, types, assoc_bindings)
     }
 
-    // No explicit region bound specified. Therefore, examine trait
-    // bounds and see if we can derive region bounds from those.
-    let derived_region_bounds =
-        object_region_bounds(tcx, &principal_trait_ref, builtin_bounds);
+    /// Returns the appropriate lifetime to use for any output lifetimes
+    /// (if one exists) and a vector of the (pattern, number of lifetimes)
+    /// corresponding to each input type/pattern.
+    fn find_implied_output_region(&self,
+                                  input_tys: &[Ty<'tcx>],
+                                  input_pats: Vec<String>) -> ElidedLifetime
+    {
+        let tcx = self.tcx();
+        let mut lifetimes_for_params = Vec::new();
+        let mut possible_implied_output_region = None;
 
-    // If there are no derived region bounds, then report back that we
-    // can find no region bound. The caller will use the default.
-    if derived_region_bounds.is_empty() {
-        return None;
+        for (input_type, input_pat) in input_tys.iter().zip(input_pats) {
+            let mut regions = FnvHashSet();
+            let have_bound_regions = tcx.collect_regions(input_type, &mut regions);
+
+            debug!("find_implied_output_regions: collected {:?} from {:?} \
+                    have_bound_regions={:?}", &regions, input_type, have_bound_regions);
+
+            if regions.len() == 1 {
+                // there's a chance that the unique lifetime of this
+                // iteration will be the appropriate lifetime for output
+                // parameters, so lets store it.
+                possible_implied_output_region = regions.iter().cloned().next();
+            }
+
+            lifetimes_for_params.push(ElisionFailureInfo {
+                name: input_pat,
+                lifetime_count: regions.len(),
+                have_bound_regions: have_bound_regions
+            });
+        }
+
+        if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::<usize>() == 1 {
+            Ok(possible_implied_output_region.unwrap())
+        } else {
+            Err(Some(lifetimes_for_params))
+        }
     }
 
-    // If any of the derived region bounds are 'static, that is always
-    // the best choice.
-    if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
-        return Some(ty::ReStatic);
+    fn convert_ty_with_lifetime_elision(&self,
+                                        elided_lifetime: ElidedLifetime,
+                                        ty: &hir::Ty)
+                                        -> Ty<'tcx>
+    {
+        match elided_lifetime {
+            Ok(implied_output_region) => {
+                let rb = ElidableRscope::new(implied_output_region);
+                self.ast_ty_to_ty(&rb, ty)
+            }
+            Err(param_lifetimes) => {
+                // All regions must be explicitly specified in the output
+                // if the lifetime elision rules do not apply. This saves
+                // the user from potentially-confusing errors.
+                let rb = UnelidableRscope::new(param_lifetimes);
+                self.ast_ty_to_ty(&rb, ty)
+            }
+        }
     }
 
-    // Determine whether there is exactly one unique region in the set
-    // of derived region bounds. If so, use that. Otherwise, report an
-    // error.
-    let r = derived_region_bounds[0];
-    if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
-        span_err!(tcx.sess, span, E0227,
-                  "ambiguous lifetime bound, explicit lifetime bound required");
+    fn convert_parenthesized_parameters(&self,
+                                        rscope: &RegionScope,
+                                        span: Span,
+                                        decl_generics: &ty::Generics<'tcx>,
+                                        data: &hir::ParenthesizedParameterData)
+                                        -> (Substs<'tcx>,
+                                            Vec<Ty<'tcx>>,
+                                            Vec<ConvertedBinding<'tcx>>)
+    {
+        let region_substs =
+            self.create_region_substs(rscope, span, decl_generics, Vec::new());
+
+        let binding_rscope = BindingRscope::new();
+        let inputs =
+            data.inputs.iter()
+                       .map(|a_t| self.ast_ty_arg_to_ty(&binding_rscope, decl_generics,
+                                                        0, &region_substs, a_t))
+                       .collect::<Vec<Ty<'tcx>>>();
+
+        let input_params = vec![String::new(); inputs.len()];
+        let implied_output_region = self.find_implied_output_region(&inputs, input_params);
+
+        let input_ty = self.tcx().mk_tup(inputs);
+
+        let (output, output_span) = match data.output {
+            Some(ref output_ty) => {
+                (self.convert_ty_with_lifetime_elision(implied_output_region, &output_ty),
+                 output_ty.span)
+            }
+            None => {
+                (self.tcx().mk_nil(), data.span)
+            }
+        };
+
+        let output_binding = ConvertedBinding {
+            item_name: token::intern(FN_OUTPUT_NAME),
+            ty: output,
+            span: output_span
+        };
+
+        (region_substs, vec![input_ty], vec![output_binding])
+    }
+
+    pub fn instantiate_poly_trait_ref(&self,
+        rscope: &RegionScope,
+        ast_trait_ref: &hir::PolyTraitRef,
+        self_ty: Option<Ty<'tcx>>,
+        poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+        -> ty::PolyTraitRef<'tcx>
+    {
+        let trait_ref = &ast_trait_ref.trait_ref;
+        let trait_def_id = self.trait_def_id(trait_ref);
+        self.ast_path_to_poly_trait_ref(rscope,
+                                        trait_ref.path.span,
+                                        PathParamMode::Explicit,
+                                        trait_def_id,
+                                        self_ty,
+                                        trait_ref.path.segments.last().unwrap(),
+                                        poly_projections)
+    }
+
+    /// Instantiates the path for the given trait reference, assuming that it's
+    /// bound to a valid trait type. Returns the def_id for the defining trait.
+    /// Fails if the type is a type other than a trait type.
+    ///
+    /// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
+    /// are disallowed. Otherwise, they are pushed onto the vector given.
+    pub fn instantiate_mono_trait_ref(&self,
+        rscope: &RegionScope,
+        trait_ref: &hir::TraitRef,
+        self_ty: Option<Ty<'tcx>>)
+        -> ty::TraitRef<'tcx>
+    {
+        let trait_def_id = self.trait_def_id(trait_ref);
+        self.ast_path_to_mono_trait_ref(rscope,
+                                        trait_ref.path.span,
+                                        PathParamMode::Explicit,
+                                        trait_def_id,
+                                        self_ty,
+                                        trait_ref.path.segments.last().unwrap())
+    }
+
+    fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId {
+        let path = &trait_ref.path;
+        match ::lookup_full_def(self.tcx(), path.span, trait_ref.ref_id) {
+            Def::Trait(trait_def_id) => trait_def_id,
+            Def::Err => {
+                self.tcx().sess.fatal("cannot continue compilation due to previous error");
+            }
+            _ => {
+                span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait",
+                            path);
+            }
+        }
+    }
+
+    fn object_path_to_poly_trait_ref(&self,
+        rscope: &RegionScope,
+        span: Span,
+        param_mode: PathParamMode,
+        trait_def_id: DefId,
+        trait_segment: &hir::PathSegment,
+        mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+        -> ty::PolyTraitRef<'tcx>
+    {
+        self.ast_path_to_poly_trait_ref(rscope,
+                                        span,
+                                        param_mode,
+                                        trait_def_id,
+                                        None,
+                                        trait_segment,
+                                        projections)
+    }
+
+    fn ast_path_to_poly_trait_ref(&self,
+        rscope: &RegionScope,
+        span: Span,
+        param_mode: PathParamMode,
+        trait_def_id: DefId,
+        self_ty: Option<Ty<'tcx>>,
+        trait_segment: &hir::PathSegment,
+        poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+        -> ty::PolyTraitRef<'tcx>
+    {
+        debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment);
+        // The trait reference introduces a binding level here, so
+        // we need to shift the `rscope`. It'd be nice if we could
+        // do away with this rscope stuff and work this knowledge
+        // into resolve_lifetimes, as we do with non-omitted
+        // lifetimes. Oh well, not there yet.
+        let shifted_rscope = &ShiftedRscope::new(rscope);
+
+        let (substs, assoc_bindings) =
+            self.create_substs_for_ast_trait_ref(shifted_rscope,
+                                                 span,
+                                                 param_mode,
+                                                 trait_def_id,
+                                                 self_ty,
+                                                 trait_segment);
+        let poly_trait_ref = ty::Binder(ty::TraitRef::new(trait_def_id, substs));
+
+        {
+            let converted_bindings =
+                assoc_bindings
+                .iter()
+                .filter_map(|binding| {
+                    // specify type to assert that error was already reported in Err case:
+                    let predicate: Result<_, ErrorReported> =
+                        self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref.clone(),
+                                                                           self_ty,
+                                                                           binding);
+                    predicate.ok() // ok to ignore Err() because ErrorReported (see above)
+                });
+            poly_projections.extend(converted_bindings);
+        }
+
+        debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}",
+               trait_segment, poly_projections, poly_trait_ref);
+        poly_trait_ref
+    }
+
+    fn ast_path_to_mono_trait_ref(&self,
+                                  rscope: &RegionScope,
+                                  span: Span,
+                                  param_mode: PathParamMode,
+                                  trait_def_id: DefId,
+                                  self_ty: Option<Ty<'tcx>>,
+                                  trait_segment: &hir::PathSegment)
+                                  -> ty::TraitRef<'tcx>
+    {
+        let (substs, assoc_bindings) =
+            self.create_substs_for_ast_trait_ref(rscope,
+                                                 span,
+                                                 param_mode,
+                                                 trait_def_id,
+                                                 self_ty,
+                                                 trait_segment);
+        assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
+        ty::TraitRef::new(trait_def_id, substs)
+    }
+
+    fn create_substs_for_ast_trait_ref(&self,
+                                       rscope: &RegionScope,
+                                       span: Span,
+                                       param_mode: PathParamMode,
+                                       trait_def_id: DefId,
+                                       self_ty: Option<Ty<'tcx>>,
+                                       trait_segment: &hir::PathSegment)
+                                       -> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
+    {
+        debug!("create_substs_for_ast_trait_ref(trait_segment={:?})",
+               trait_segment);
+
+        let trait_def = match self.get_trait_def(span, trait_def_id) {
+            Ok(trait_def) => trait_def,
+            Err(ErrorReported) => {
+                // No convenient way to recover from a cycle here. Just bail. Sorry!
+                self.tcx().sess.abort_if_errors();
+                bug!("ErrorReported returned, but no errors reports?")
+            }
+        };
+
+        let (regions, types, assoc_bindings) = match trait_segment.parameters {
+            hir::AngleBracketedParameters(ref data) => {
+                // For now, require that parenthetical notation be used
+                // only with `Fn()` etc.
+                if !self.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar {
+                    emit_feature_err(&self.tcx().sess.parse_sess.span_diagnostic,
+                                     "unboxed_closures", span, GateIssue::Language,
+                                     "\
+                        the precise format of `Fn`-family traits' \
+                        type parameters is subject to change. \
+                        Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead");
+                }
+
+                self.convert_angle_bracketed_parameters(rscope, span, &trait_def.generics, data)
+            }
+            hir::ParenthesizedParameters(ref data) => {
+                // For now, require that parenthetical notation be used
+                // only with `Fn()` etc.
+                if !self.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar {
+                    emit_feature_err(&self.tcx().sess.parse_sess.span_diagnostic,
+                                     "unboxed_closures", span, GateIssue::Language,
+                                     "\
+                        parenthetical notation is only stable when used with `Fn`-family traits");
+                }
+
+                self.convert_parenthesized_parameters(rscope, span, &trait_def.generics, data)
+            }
+        };
+
+        let substs = self.create_substs_for_ast_path(span,
+                                                     param_mode,
+                                                     &trait_def.generics,
+                                                     self_ty,
+                                                     types,
+                                                     regions);
+
+        (self.tcx().mk_substs(substs), assoc_bindings)
+    }
+
+    fn ast_type_binding_to_poly_projection_predicate(&self,
+        mut trait_ref: ty::PolyTraitRef<'tcx>,
+        self_ty: Option<Ty<'tcx>>,
+        binding: &ConvertedBinding<'tcx>)
+        -> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
+    {
+        let tcx = self.tcx();
+
+        // Given something like `U : SomeTrait<T=X>`, we want to produce a
+        // predicate like `<U as SomeTrait>::T = X`. This is somewhat
+        // subtle in the event that `T` is defined in a supertrait of
+        // `SomeTrait`, because in that case we need to upcast.
+        //
+        // That is, consider this case:
+        //
+        // ```
+        // trait SubTrait : SuperTrait<int> { }
+        // trait SuperTrait<A> { type T; }
+        //
+        // ... B : SubTrait<T=foo> ...
+        // ```
+        //
+        // We want to produce `<B as SuperTrait<int>>::T == foo`.
+
+        // Simple case: X is defined in the current trait.
+        if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
+            return Ok(ty::Binder(ty::ProjectionPredicate {      // <-------------------+
+                projection_ty: ty::ProjectionTy {               //                     |
+                    trait_ref: trait_ref.skip_binder().clone(), // Binder moved here --+
+                    item_name: binding.item_name,
+                },
+                ty: binding.ty,
+            }));
+        }
+
+        // Otherwise, we have to walk through the supertraits to find
+        // those that do.  This is complicated by the fact that, for an
+        // object type, the `Self` type is not present in the
+        // substitutions (after all, it's being constructed right now),
+        // but the `supertraits` iterator really wants one. To handle
+        // this, we currently insert a dummy type and then remove it
+        // later. Yuck.
+
+        let dummy_self_ty = tcx.mk_infer(ty::FreshTy(0));
+        if self_ty.is_none() { // if converting for an object type
+            let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+
+            assert!(dummy_substs.self_ty().is_none());                     //                    |
+            dummy_substs.types.push(SelfSpace, dummy_self_ty);             //                    |
+            trait_ref = ty::Binder(ty::TraitRef::new(trait_ref.def_id(),   // <------------+
+                                                     tcx.mk_substs(dummy_substs)));
+        }
+
+        self.ensure_super_predicates(binding.span, trait_ref.def_id())?;
+
+        let mut candidates: Vec<ty::PolyTraitRef> =
+            traits::supertraits(tcx, trait_ref.clone())
+            .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name))
+            .collect();
+
+        // If converting for an object type, then remove the dummy-ty from `Self` now.
+        // Yuckety yuck.
+        if self_ty.is_none() {
+            for candidate in &mut candidates {
+                let mut dummy_substs = candidate.0.substs.clone();
+                assert!(dummy_substs.self_ty() == Some(dummy_self_ty));
+                dummy_substs.types.pop(SelfSpace);
+                *candidate = ty::Binder(ty::TraitRef::new(candidate.def_id(),
+                                                          tcx.mk_substs(dummy_substs)));
+            }
+        }
+
+        let candidate = self.one_bound_for_assoc_type(candidates,
+                                                      &trait_ref.to_string(),
+                                                      &binding.item_name.as_str(),
+                                                      binding.span)?;
+
+        Ok(ty::Binder(ty::ProjectionPredicate {             // <-------------------------+
+            projection_ty: ty::ProjectionTy {               //                           |
+                trait_ref: candidate.skip_binder().clone(), // binder is moved up here --+
+                item_name: binding.item_name,
+            },
+            ty: binding.ty,
+        }))
+    }
+
+    fn ast_path_to_ty(&self,
+        rscope: &RegionScope,
+        span: Span,
+        param_mode: PathParamMode,
+        did: DefId,
+        item_segment: &hir::PathSegment)
+        -> Ty<'tcx>
+    {
+        let tcx = self.tcx();
+        let (generics, decl_ty) = match self.get_item_type_scheme(span, did) {
+            Ok(ty::TypeScheme { generics,  ty: decl_ty }) => {
+                (generics, decl_ty)
+            }
+            Err(ErrorReported) => {
+                return tcx.types.err;
+            }
+        };
+
+        let substs = self.ast_path_substs_for_ty(rscope,
+                                                 span,
+                                                 param_mode,
+                                                 &generics,
+                                                 item_segment);
+
+        // FIXME(#12938): This is a hack until we have full support for DST.
+        if Some(did) == self.tcx().lang_items.owned_box() {
+            assert_eq!(substs.types.len(TypeSpace), 1);
+            return self.tcx().mk_box(*substs.types.get(TypeSpace, 0));
+        }
+
+        decl_ty.subst(self.tcx(), &substs)
+    }
+
+    fn ast_ty_to_trait_ref(&self,
+                           rscope: &RegionScope,
+                           ty: &hir::Ty,
+                           bounds: &[hir::TyParamBound])
+                           -> Result<TraitAndProjections<'tcx>, ErrorReported>
+    {
+        /*!
+         * In a type like `Foo + Send`, we want to wait to collect the
+         * full set of bounds before we make the object type, because we
+         * need them to infer a region bound.  (For example, if we tried
+         * made a type from just `Foo`, then it wouldn't be enough to
+         * infer a 'static bound, and hence the user would get an error.)
+         * So this function is used when we're dealing with a sum type to
+         * convert the LHS. It only accepts a type that refers to a trait
+         * name, and reports an error otherwise.
+         */
+
+        match ty.node {
+            hir::TyPath(None, ref path) => {
+                let def = match self.tcx().def_map.borrow().get(&ty.id) {
+                    Some(&def::PathResolution { base_def, depth: 0, .. }) => Some(base_def),
+                    _ => None
+                };
+                match def {
+                    Some(Def::Trait(trait_def_id)) => {
+                        let mut projection_bounds = Vec::new();
+                        let trait_ref =
+                            self.object_path_to_poly_trait_ref(rscope,
+                                                               path.span,
+                                                               PathParamMode::Explicit,
+                                                               trait_def_id,
+                                                               path.segments.last().unwrap(),
+                                                               &mut projection_bounds);
+                        Ok((trait_ref, projection_bounds))
+                    }
+                    _ => {
+                        span_err!(self.tcx().sess, ty.span, E0172,
+                                  "expected a reference to a trait");
+                        Err(ErrorReported)
+                    }
+                }
+            }
+            _ => {
+                let mut err = struct_span_err!(self.tcx().sess, ty.span, E0178,
+                                               "expected a path on the left-hand side \
+                                                of `+`, not `{}`",
+                                               pprust::ty_to_string(ty));
+                let hi = bounds.iter().map(|x| match *x {
+                    hir::TraitTyParamBound(ref tr, _) => tr.span.hi,
+                    hir::RegionTyParamBound(ref r) => r.span.hi,
+                }).max_by_key(|x| x.to_usize());
+                let full_span = hi.map(|hi| Span {
+                    lo: ty.span.lo,
+                    hi: hi,
+                    expn_id: ty.span.expn_id,
+                });
+                match (&ty.node, full_span) {
+                    (&hir::TyRptr(None, ref mut_ty), Some(full_span)) => {
+                        let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
+                        err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
+                                            format!("&{}({} +{})",
+                                                    mutbl_str,
+                                                    pprust::ty_to_string(&mut_ty.ty),
+                                                    pprust::bounds_to_string(bounds)));
+                    }
+                    (&hir::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
+                        let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
+                        err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
+                                            format!("&{} {}({} +{})",
+                                                    pprust::lifetime_to_string(lt),
+                                                    mutbl_str,
+                                                    pprust::ty_to_string(&mut_ty.ty),
+                                                    pprust::bounds_to_string(bounds)));
+                    }
+
+                    _ => {
+                        help!(&mut err,
+                                   "perhaps you forgot parentheses? (per RFC 438)");
+                    }
+                }
+                err.emit();
+                Err(ErrorReported)
+            }
+        }
+    }
+
+    fn trait_ref_to_object_type(&self,
+                                rscope: &RegionScope,
+                                span: Span,
+                                trait_ref: ty::PolyTraitRef<'tcx>,
+                                projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
+                                bounds: &[hir::TyParamBound])
+                                -> Ty<'tcx>
+    {
+        let existential_bounds = self.conv_existential_bounds(rscope,
+                                                              span,
+                                                              trait_ref.clone(),
+                                                              projection_bounds,
+                                                              bounds);
+
+        let result = self.make_object_type(span, trait_ref, existential_bounds);
+        debug!("trait_ref_to_object_type: result={:?}",
+               result);
+
+        result
+    }
+
+    fn make_object_type(&self,
+                        span: Span,
+                        principal: ty::PolyTraitRef<'tcx>,
+                        bounds: ty::ExistentialBounds<'tcx>)
+                        -> Ty<'tcx> {
+        let tcx = self.tcx();
+        let object = ty::TraitTy {
+            principal: principal,
+            bounds: bounds
+        };
+        let object_trait_ref =
+            object.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
+
+        // ensure the super predicates and stop if we encountered an error
+        if self.ensure_super_predicates(span, principal.def_id()).is_err() {
+            return tcx.types.err;
+        }
+
+        // check that there are no gross object safety violations,
+        // most importantly, that the supertraits don't contain Self,
+        // to avoid ICE-s.
+        let object_safety_violations =
+            tcx.astconv_object_safety_violations(principal.def_id());
+        if !object_safety_violations.is_empty() {
+            tcx.report_object_safety_error(
+                span, principal.def_id(), None, object_safety_violations)
+                .unwrap().emit();
+            return tcx.types.err;
+        }
+
+        let mut associated_types: FnvHashSet<(DefId, ast::Name)> =
+            traits::supertraits(tcx, object_trait_ref)
+            .flat_map(|tr| {
+                let trait_def = tcx.lookup_trait_def(tr.def_id());
+                trait_def.associated_type_names
+                    .clone()
+                    .into_iter()
+                    .map(move |associated_type_name| (tr.def_id(), associated_type_name))
+            })
+            .collect();
+
+        for projection_bound in &object.bounds.projection_bounds {
+            let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
+                        projection_bound.0.projection_ty.item_name);
+            associated_types.remove(&pair);
+        }
+
+        for (trait_def_id, name) in associated_types {
+            span_err!(tcx.sess, span, E0191,
+                "the value of the associated type `{}` (from the trait `{}`) must be specified",
+                        name,
+                        tcx.item_path_str(trait_def_id));
+        }
+
+        tcx.mk_trait(object.principal, object.bounds)
+    }
+
+    fn report_ambiguous_associated_type(&self,
+                                        span: Span,
+                                        type_str: &str,
+                                        trait_str: &str,
+                                        name: &str) {
+        span_err!(self.tcx().sess, span, E0223,
+                  "ambiguous associated type; specify the type using the syntax \
+                   `<{} as {}>::{}`",
+                  type_str, trait_str, name);
+    }
+
+    // Search for a bound on a type parameter which includes the associated item
+    // given by assoc_name. ty_param_node_id is the node id for the type parameter
+    // (which might be `Self`, but only if it is the `Self` of a trait, not an
+    // impl). This function will fail if there are no suitable bounds or there is
+    // any ambiguity.
+    fn find_bound_for_assoc_item(&self,
+                                 ty_param_node_id: ast::NodeId,
+                                 ty_param_name: ast::Name,
+                                 assoc_name: ast::Name,
+                                 span: Span)
+                                 -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
+    {
+        let tcx = self.tcx();
+
+        let bounds = match self.get_type_parameter_bounds(span, ty_param_node_id) {
+            Ok(v) => v,
+            Err(ErrorReported) => {
+                return Err(ErrorReported);
+            }
+        };
+
+        // Ensure the super predicates and stop if we encountered an error.
+        if bounds.iter().any(|b| self.ensure_super_predicates(span, b.def_id()).is_err()) {
+            return Err(ErrorReported);
+        }
+
+        // Check that there is exactly one way to find an associated type with the
+        // correct name.
+        let suitable_bounds: Vec<_> =
+            traits::transitive_bounds(tcx, &bounds)
+            .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name))
+            .collect();
+
+        self.one_bound_for_assoc_type(suitable_bounds,
+                                      &ty_param_name.as_str(),
+                                      &assoc_name.as_str(),
+                                      span)
+    }
+
+
+    // Checks that bounds contains exactly one element and reports appropriate
+    // errors otherwise.
+    fn one_bound_for_assoc_type(&self,
+                                bounds: Vec<ty::PolyTraitRef<'tcx>>,
+                                ty_param_name: &str,
+                                assoc_name: &str,
+                                span: Span)
+        -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
+    {
+        if bounds.is_empty() {
+            span_err!(self.tcx().sess, span, E0220,
+                      "associated type `{}` not found for `{}`",
+                      assoc_name,
+                      ty_param_name);
+            return Err(ErrorReported);
+        }
+
+        if bounds.len() > 1 {
+            let mut err = struct_span_err!(self.tcx().sess, span, E0221,
+                                           "ambiguous associated type `{}` in bounds of `{}`",
+                                           assoc_name,
+                                           ty_param_name);
+
+            for bound in &bounds {
+                span_note!(&mut err, span,
+                           "associated type `{}` could derive from `{}`",
+                           ty_param_name,
+                           bound);
+            }
+            err.emit();
+        }
+
+        Ok(bounds[0].clone())
+    }
+
+    // Create a type from a path to an associated type.
+    // For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C
+    // and item_segment is the path segment for D. We return a type and a def for
+    // the whole path.
+    // Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type
+    // parameter or Self.
+    fn associated_path_def_to_ty(&self,
+                                 span: Span,
+                                 ty: Ty<'tcx>,
+                                 ty_path_def: Def,
+                                 item_segment: &hir::PathSegment)
+                                 -> (Ty<'tcx>, Def)
+    {
+        let tcx = self.tcx();
+        let assoc_name = item_segment.identifier.name;
+
+        debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
+
+        tcx.prohibit_type_params(slice::ref_slice(item_segment));
+
+        // Find the type of the associated item, and the trait where the associated
+        // item is declared.
+        let bound = match (&ty.sty, ty_path_def) {
+            (_, Def::SelfTy(Some(trait_did), Some(impl_id))) => {
+                // `Self` in an impl of a trait - we have a concrete self type and a
+                // trait reference.
+                let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap();
+                let trait_ref = if let Some(free_substs) = self.get_free_substs() {
+                    trait_ref.subst(tcx, free_substs)
+                } else {
+                    trait_ref
+                };
+
+                if self.ensure_super_predicates(span, trait_did).is_err() {
+                    return (tcx.types.err, ty_path_def);
+                }
+
+                let candidates: Vec<ty::PolyTraitRef> =
+                    traits::supertraits(tcx, ty::Binder(trait_ref))
+                    .filter(|r| self.trait_defines_associated_type_named(r.def_id(),
+                                                                         assoc_name))
+                    .collect();
+
+                match self.one_bound_for_assoc_type(candidates,
+                                                    "Self",
+                                                    &assoc_name.as_str(),
+                                                    span) {
+                    Ok(bound) => bound,
+                    Err(ErrorReported) => return (tcx.types.err, ty_path_def),
+                }
+            }
+            (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
+                let trait_node_id = tcx.map.as_local_node_id(trait_did).unwrap();
+                match self.find_bound_for_assoc_item(trait_node_id,
+                                                     keywords::SelfType.name(),
+                                                     assoc_name,
+                                                     span) {
+                    Ok(bound) => bound,
+                    Err(ErrorReported) => return (tcx.types.err, ty_path_def),
+                }
+            }
+            (&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => {
+                let param_node_id = tcx.map.as_local_node_id(param_did).unwrap();
+                match self.find_bound_for_assoc_item(param_node_id,
+                                                     param_name,
+                                                     assoc_name,
+                                                     span) {
+                    Ok(bound) => bound,
+                    Err(ErrorReported) => return (tcx.types.err, ty_path_def),
+                }
+            }
+            _ => {
+                self.report_ambiguous_associated_type(span,
+                                                      &ty.to_string(),
+                                                      "Trait",
+                                                      &assoc_name.as_str());
+                return (tcx.types.err, ty_path_def);
+            }
+        };
+
+        let trait_did = bound.0.def_id;
+        let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
+
+        let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) {
+            // `ty::trait_items` used below requires information generated
+            // by type collection, which may be in progress at this point.
+            match tcx.map.expect_item(trait_id).node {
+                hir::ItemTrait(_, _, _, ref trait_items) => {
+                    let item = trait_items.iter()
+                                          .find(|i| i.name == assoc_name)
+                                          .expect("missing associated type");
+                    tcx.map.local_def_id(item.id)
+                }
+                _ => bug!()
+            }
+        } else {
+            let trait_items = tcx.trait_items(trait_did);
+            let item = trait_items.iter().find(|i| i.name() == assoc_name);
+            item.expect("missing associated type").def_id()
+        };
+
+        (ty, Def::AssociatedTy(trait_did, item_did))
+    }
+
+    fn qpath_to_ty(&self,
+                   rscope: &RegionScope,
+                   span: Span,
+                   param_mode: PathParamMode,
+                   opt_self_ty: Option<Ty<'tcx>>,
+                   trait_def_id: DefId,
+                   trait_segment: &hir::PathSegment,
+                   item_segment: &hir::PathSegment)
+                   -> Ty<'tcx>
+    {
+        let tcx = self.tcx();
+
+        tcx.prohibit_type_params(slice::ref_slice(item_segment));
+
+        let self_ty = if let Some(ty) = opt_self_ty {
+            ty
+        } else {
+            let path_str = tcx.item_path_str(trait_def_id);
+            self.report_ambiguous_associated_type(span,
+                                                  "Type",
+                                                  &path_str,
+                                                  &item_segment.identifier.name.as_str());
+            return tcx.types.err;
+        };
+
+        debug!("qpath_to_ty: self_type={:?}", self_ty);
+
+        let trait_ref = self.ast_path_to_mono_trait_ref(rscope,
+                                                        span,
+                                                        param_mode,
+                                                        trait_def_id,
+                                                        Some(self_ty),
+                                                        trait_segment);
+
+        debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
+
+        self.projected_ty(span, trait_ref, item_segment.identifier.name)
+    }
+
+    /// Convert a type supplied as value for a type argument from AST into our
+    /// our internal representation. This is the same as `ast_ty_to_ty` but that
+    /// it applies the object lifetime default.
+    ///
+    /// # Parameters
+    ///
+    /// * `this`, `rscope`: the surrounding context
+    /// * `decl_generics`: the generics of the struct/enum/trait declaration being
+    ///   referenced
+    /// * `index`: the index of the type parameter being instantiated from the list
+    ///   (we assume it is in the `TypeSpace`)
+    /// * `region_substs`: a partial substitution consisting of
+    ///   only the region type parameters being supplied to this type.
+    /// * `ast_ty`: the ast representation of the type being supplied
+    pub fn ast_ty_arg_to_ty(&self,
+                            rscope: &RegionScope,
+                            decl_generics: &ty::Generics<'tcx>,
+                            index: usize,
+                            region_substs: &Substs<'tcx>,
+                            ast_ty: &hir::Ty)
+                            -> Ty<'tcx>
+    {
+        let tcx = self.tcx();
+
+        if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) {
+            let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs);
+            let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default);
+            self.ast_ty_to_ty(rscope1, ast_ty)
+        } else {
+            self.ast_ty_to_ty(rscope, ast_ty)
+        }
+    }
+
+    // Check the base def in a PathResolution and convert it to a Ty. If there are
+    // associated types in the PathResolution, these will need to be separately
+    // resolved.
+    fn base_def_to_ty(&self,
+                      rscope: &RegionScope,
+                      span: Span,
+                      param_mode: PathParamMode,
+                      def: &Def,
+                      opt_self_ty: Option<Ty<'tcx>>,
+                      base_segments: &[hir::PathSegment])
+                      -> Ty<'tcx> {
+        let tcx = self.tcx();
+
+        match *def {
+            Def::Trait(trait_def_id) => {
+                // N.B. this case overlaps somewhat with
+                // TyObjectSum, see that fn for details
+                let mut projection_bounds = Vec::new();
+
+                let trait_ref =
+                    self.object_path_to_poly_trait_ref(rscope,
+                                                       span,
+                                                       param_mode,
+                                                       trait_def_id,
+                                                       base_segments.last().unwrap(),
+                                                       &mut projection_bounds);
+
+                tcx.prohibit_type_params(base_segments.split_last().unwrap().1);
+                self.trait_ref_to_object_type(rscope,
+                                              span,
+                                              trait_ref,
+                                              projection_bounds,
+                                              &[])
+            }
+            Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
+                tcx.prohibit_type_params(base_segments.split_last().unwrap().1);
+                self.ast_path_to_ty(rscope,
+                                    span,
+                                    param_mode,
+                                    did,
+                                    base_segments.last().unwrap())
+            }
+            Def::TyParam(space, index, _, name) => {
+                tcx.prohibit_type_params(base_segments);
+                tcx.mk_param(space, index, name)
+            }
+            Def::SelfTy(_, Some(impl_id)) => {
+                // Self in impl (we know the concrete type).
+                tcx.prohibit_type_params(base_segments);
+                let ty = tcx.node_id_to_type(impl_id);
+                if let Some(free_substs) = self.get_free_substs() {
+                    ty.subst(tcx, free_substs)
+                } else {
+                    ty
+                }
+            }
+            Def::SelfTy(Some(_), None) => {
+                // Self in trait.
+                tcx.prohibit_type_params(base_segments);
+                tcx.mk_self_type()
+            }
+            Def::AssociatedTy(trait_did, _) => {
+                tcx.prohibit_type_params(&base_segments[..base_segments.len()-2]);
+                self.qpath_to_ty(rscope,
+                                 span,
+                                 param_mode,
+                                 opt_self_ty,
+                                 trait_did,
+                                 &base_segments[base_segments.len()-2],
+                                 base_segments.last().unwrap())
+            }
+            Def::Mod(..) => {
+                // Used as sentinel by callers to indicate the `<T>::A::B::C` form.
+                // FIXME(#22519) This part of the resolution logic should be
+                // avoided entirely for that form, once we stop needed a Def
+                // for `associated_path_def_to_ty`.
+                // Fixing this will also let use resolve <Self>::Foo the same way we
+                // resolve Self::Foo, at the moment we can't resolve the former because
+                // we don't have the trait information around, which is just sad.
+
+                assert!(base_segments.is_empty());
+
+                opt_self_ty.expect("missing T in <T>::a::b::c")
+            }
+            Def::PrimTy(prim_ty) => {
+                tcx.prim_ty_to_ty(base_segments, prim_ty)
+            }
+            Def::Err => {
+                self.set_tainted_by_errors();
+                return self.tcx().types.err;
+            }
+            _ => {
+                span_err!(tcx.sess, span, E0248,
+                          "found value `{}` used as a type",
+                          tcx.item_path_str(def.def_id()));
+                return self.tcx().types.err;
+            }
+        }
+    }
+
+    // Note that both base_segments and assoc_segments may be empty, although not at
+    // the same time.
+    pub fn finish_resolving_def_to_ty(&self,
+                                      rscope: &RegionScope,
+                                      span: Span,
+                                      param_mode: PathParamMode,
+                                      def: &Def,
+                                      opt_self_ty: Option<Ty<'tcx>>,
+                                      base_segments: &[hir::PathSegment],
+                                      assoc_segments: &[hir::PathSegment])
+                                      -> Ty<'tcx> {
+        let mut ty = self.base_def_to_ty(rscope,
+                                         span,
+                                         param_mode,
+                                         def,
+                                         opt_self_ty,
+                                         base_segments);
+        let mut def = *def;
+        // If any associated type segments remain, attempt to resolve them.
+        for segment in assoc_segments {
+            if ty.sty == ty::TyError {
+                break;
+            }
+            // This is pretty bad (it will fail except for T::A and Self::A).
+            let (a_ty, a_def) = self.associated_path_def_to_ty(span,
+                                                               ty,
+                                                               def,
+                                                               segment);
+            ty = a_ty;
+            def = a_def;
+        }
+        ty
+    }
+
+    /// Parses the programmer's textual representation of a type into our
+    /// internal notion of a type.
+    pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
+        debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})",
+               ast_ty.id, ast_ty);
+
+        let tcx = self.tcx();
+
+        match ast_ty.node {
+            hir::TyVec(ref ty) => {
+                tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty))
+            }
+            hir::TyObjectSum(ref ty, ref bounds) => {
+                match self.ast_ty_to_trait_ref(rscope, &ty, bounds) {
+                    Ok((trait_ref, projection_bounds)) => {
+                        self.trait_ref_to_object_type(rscope,
+                                                      ast_ty.span,
+                                                      trait_ref,
+                                                      projection_bounds,
+                                                      bounds)
+                    }
+                    Err(ErrorReported) => {
+                        self.tcx().types.err
+                    }
+                }
+            }
+            hir::TyPtr(ref mt) => {
+                tcx.mk_ptr(ty::TypeAndMut {
+                    ty: self.ast_ty_to_ty(rscope, &mt.ty),
+                    mutbl: mt.mutbl
+                })
+            }
+            hir::TyRptr(ref region, ref mt) => {
+                let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region);
+                debug!("TyRef r={:?}", r);
+                let rscope1 =
+                    &ObjectLifetimeDefaultRscope::new(
+                        rscope,
+                        ty::ObjectLifetimeDefault::Specific(r));
+                let t = self.ast_ty_to_ty(rscope1, &mt.ty);
+                tcx.mk_ref(tcx.mk_region(r), ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
+            }
+            hir::TyTup(ref fields) => {
+                let flds = fields.iter()
+                                 .map(|t| self.ast_ty_to_ty(rscope, &t))
+                                 .collect();
+                tcx.mk_tup(flds)
+            }
+            hir::TyBareFn(ref bf) => {
+                require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
+                tcx.mk_fn_ptr(self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl))
+            }
+            hir::TyPolyTraitRef(ref bounds) => {
+                self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds)
+            }
+            hir::TyPath(ref maybe_qself, ref path) => {
+                let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) {
+                    d
+                } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
+                    // Create some fake resolution that can't possibly be a type.
+                    def::PathResolution {
+                        base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
+                        depth: path.segments.len()
+                    }
+                } else {
+                    span_bug!(ast_ty.span, "unbound path {:?}", ast_ty)
+                };
+                let def = path_res.base_def;
+                let base_ty_end = path.segments.len() - path_res.depth;
+                let opt_self_ty = maybe_qself.as_ref().map(|qself| {
+                    self.ast_ty_to_ty(rscope, &qself.ty)
+                });
+                let ty = self.finish_resolving_def_to_ty(rscope,
+                                                         ast_ty.span,
+                                                         PathParamMode::Explicit,
+                                                         &def,
+                                                         opt_self_ty,
+                                                         &path.segments[..base_ty_end],
+                                                         &path.segments[base_ty_end..]);
+
+                if path_res.depth != 0 && ty.sty != ty::TyError {
+                    // Write back the new resolution.
+                    tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution {
+                        base_def: def,
+                        depth: 0
+                    });
+                }
+
+                ty
+            }
+            hir::TyFixedLengthVec(ref ty, ref e) => {
+                let hint = UncheckedExprHint(tcx.types.usize);
+                match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) {
+                    Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
+                        let i = i.as_u64(tcx.sess.target.uint_type);
+                        assert_eq!(i as usize as u64, i);
+                        tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize)
+                    },
+                    Ok(val) => {
+                        span_err!(tcx.sess, ast_ty.span, E0249,
+                                  "expected usize value for array length, got {}",
+                                  val.description());
+                        self.tcx().types.err
+                    },
+                    // array length errors happen before the global constant check
+                    // so we need to report the real error
+                    Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) |
+                    Err(r) => {
+                        let mut err = struct_span_err!(tcx.sess, r.span, E0250,
+                                                       "array length constant \
+                                                        evaluation error: {}",
+                                                       r.description());
+                        if !ast_ty.span.contains(r.span) {
+                            span_note!(&mut err, ast_ty.span, "for array length here")
+                        }
+                        err.emit();
+                        self.tcx().types.err
+                    }
+                }
+            }
+            hir::TyTypeof(ref _e) => {
+                span_err!(tcx.sess, ast_ty.span, E0516,
+                      "`typeof` is a reserved keyword but unimplemented");
+                tcx.types.err
+            }
+            hir::TyInfer => {
+                // TyInfer also appears as the type of arguments or return
+                // values in a ExprClosure, or as
+                // the type of local variables. Both of these cases are
+                // handled specially and will not descend into this routine.
+                self.ty_infer(None, None, None, ast_ty.span)
+            }
+        }
+    }
+
+    pub fn ty_of_arg(&self,
+                     rscope: &RegionScope,
+                     a: &hir::Arg,
+                     expected_ty: Option<Ty<'tcx>>)
+                     -> Ty<'tcx>
+    {
+        match a.ty.node {
+            hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
+            hir::TyInfer => self.ty_infer(None, None, None, a.ty.span),
+            _ => self.ast_ty_to_ty(rscope, &a.ty),
+        }
+    }
+
+    pub fn ty_of_method(&self,
+                        sig: &hir::MethodSig,
+                        untransformed_self_ty: Ty<'tcx>)
+                        -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
+        let self_info = Some(SelfInfo {
+            untransformed_self_ty: untransformed_self_ty,
+            explicit_self: &sig.explicit_self,
+        });
+        let (bare_fn_ty, optional_explicit_self_category) =
+            self.ty_of_method_or_bare_fn(sig.unsafety,
+                                         sig.abi,
+                                         self_info,
+                                         &sig.decl);
+        (bare_fn_ty, optional_explicit_self_category.unwrap())
+    }
+
+    pub fn ty_of_bare_fn(&self,
+                         unsafety: hir::Unsafety, abi: abi::Abi,
+                         decl: &hir::FnDecl)
+                         -> &'tcx ty::BareFnTy<'tcx> {
+        let (bare_fn_ty, _) = self.ty_of_method_or_bare_fn(unsafety, abi, None, decl);
+        bare_fn_ty
+    }
+
+    fn ty_of_method_or_bare_fn<'a>(&self,
+                                   unsafety: hir::Unsafety,
+                                   abi: abi::Abi,
+                                   opt_self_info: Option<SelfInfo<'a, 'tcx>>,
+                                   decl: &hir::FnDecl)
+                                   -> (&'tcx ty::BareFnTy<'tcx>,
+                                       Option<ty::ExplicitSelfCategory>)
+    {
+        debug!("ty_of_method_or_bare_fn");
+
+        // New region names that appear inside of the arguments of the function
+        // declaration are bound to that function type.
+        let rb = rscope::BindingRscope::new();
+
+        // `implied_output_region` is the region that will be assumed for any
+        // region parameters in the return type. In accordance with the rules for
+        // lifetime elision, we can determine it in two ways. First (determined
+        // here), if self is by-reference, then the implied output region is the
+        // region of the self parameter.
+        let (self_ty, explicit_self_category) = match opt_self_info {
+            None => (None, None),
+            Some(self_info) => self.determine_self_type(&rb, self_info)
+        };
+
+        // HACK(eddyb) replace the fake self type in the AST with the actual type.
+        let arg_params = if self_ty.is_some() {
+            &decl.inputs[1..]
+        } else {
+            &decl.inputs[..]
+        };
+        let arg_tys: Vec<Ty> =
+            arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
+        let arg_pats: Vec<String> =
+            arg_params.iter().map(|a| pprust::pat_to_string(&a.pat)).collect();
+
+        // Second, if there was exactly one lifetime (either a substitution or a
+        // reference) in the arguments, then any anonymous regions in the output
+        // have that lifetime.
+        let implied_output_region = match explicit_self_category {
+            Some(ty::ExplicitSelfCategory::ByReference(region, _)) => Ok(region),
+            _ => self.find_implied_output_region(&arg_tys, arg_pats)
+        };
+
+        let output_ty = match decl.output {
+            hir::Return(ref output) =>
+                ty::FnConverging(self.convert_ty_with_lifetime_elision(implied_output_region,
+                                                                       &output)),
+            hir::DefaultReturn(..) => ty::FnConverging(self.tcx().mk_nil()),
+            hir::NoReturn(..) => ty::FnDiverging
+        };
+
+        (self.tcx().mk_bare_fn(ty::BareFnTy {
+            unsafety: unsafety,
+            abi: abi,
+            sig: ty::Binder(ty::FnSig {
+                inputs: self_ty.into_iter().chain(arg_tys).collect(),
+                output: output_ty,
+                variadic: decl.variadic
+            }),
+        }), explicit_self_category)
+    }
+
+    fn determine_self_type<'a>(&self,
+                               rscope: &RegionScope,
+                               self_info: SelfInfo<'a, 'tcx>)
+                               -> (Option<Ty<'tcx>>, Option<ty::ExplicitSelfCategory>)
+    {
+        let self_ty = self_info.untransformed_self_ty;
+        return match self_info.explicit_self.node {
+            hir::SelfStatic => (None, Some(ty::ExplicitSelfCategory::Static)),
+            hir::SelfValue(_) => {
+                (Some(self_ty), Some(ty::ExplicitSelfCategory::ByValue))
+            }
+            hir::SelfRegion(ref lifetime, mutability, _) => {
+                let region =
+                    self.opt_ast_region_to_region(rscope,
+                                                  self_info.explicit_self.span,
+                                                  lifetime);
+                (Some(self.tcx().mk_ref(
+                    self.tcx().mk_region(region),
+                    ty::TypeAndMut {
+                        ty: self_ty,
+                        mutbl: mutability
+                    })),
+                 Some(ty::ExplicitSelfCategory::ByReference(region, mutability)))
+            }
+            hir::SelfExplicit(ref ast_type, _) => {
+                let explicit_type = self.ast_ty_to_ty(rscope, &ast_type);
+
+                // We wish to (for now) categorize an explicit self
+                // declaration like `self: SomeType` into either `self`,
+                // `&self`, `&mut self`, or `Box<self>`. We do this here
+                // by some simple pattern matching. A more precise check
+                // is done later in `check_method_self_type()`.
+                //
+                // Examples:
+                //
+                // ```
+                // impl Foo for &T {
+                //     // Legal declarations:
+                //     fn method1(self: &&T); // ExplicitSelfCategory::ByReference
+                //     fn method2(self: &T); // ExplicitSelfCategory::ByValue
+                //     fn method3(self: Box<&T>); // ExplicitSelfCategory::ByBox
+                //
+                //     // Invalid cases will be caught later by `check_method_self_type`:
+                //     fn method_err1(self: &mut T); // ExplicitSelfCategory::ByReference
+                // }
+                // ```
+                //
+                // To do the check we just count the number of "modifiers"
+                // on each type and compare them. If they are the same or
+                // the impl has more, we call it "by value". Otherwise, we
+                // look at the outermost modifier on the method decl and
+                // call it by-ref, by-box as appropriate. For method1, for
+                // example, the impl type has one modifier, but the method
+                // type has two, so we end up with
+                // ExplicitSelfCategory::ByReference.
+
+                let impl_modifiers = count_modifiers(self_info.untransformed_self_ty);
+                let method_modifiers = count_modifiers(explicit_type);
+
+                debug!("determine_explicit_self_category(self_info.untransformed_self_ty={:?} \
+                       explicit_type={:?} \
+                       modifiers=({},{})",
+                       self_info.untransformed_self_ty,
+                       explicit_type,
+                       impl_modifiers,
+                       method_modifiers);
+
+                let category = if impl_modifiers >= method_modifiers {
+                    ty::ExplicitSelfCategory::ByValue
+                } else {
+                    match explicit_type.sty {
+                        ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(*r, mt.mutbl),
+                        ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox,
+                        _ => ty::ExplicitSelfCategory::ByValue,
+                    }
+                };
+
+                (Some(explicit_type), Some(category))
+            }
+        };
+
+        fn count_modifiers(ty: Ty) -> usize {
+            match ty.sty {
+                ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1,
+                ty::TyBox(t) => count_modifiers(t) + 1,
+                _ => 0,
+            }
+        }
+    }
+
+    pub fn ty_of_closure(&self,
+        unsafety: hir::Unsafety,
+        decl: &hir::FnDecl,
+        abi: abi::Abi,
+        expected_sig: Option<ty::FnSig<'tcx>>)
+        -> ty::ClosureTy<'tcx>
+    {
+        debug!("ty_of_closure(expected_sig={:?})",
+               expected_sig);
+
+        // new region names that appear inside of the fn decl are bound to
+        // that function type
+        let rb = rscope::BindingRscope::new();
+
+        let input_tys: Vec<_> = decl.inputs.iter().enumerate().map(|(i, a)| {
+            let expected_arg_ty = expected_sig.as_ref().and_then(|e| {
+                // no guarantee that the correct number of expected args
+                // were supplied
+                if i < e.inputs.len() {
+                    Some(e.inputs[i])
+                } else {
+                    None
+                }
+            });
+            self.ty_of_arg(&rb, a, expected_arg_ty)
+        }).collect();
+
+        let expected_ret_ty = expected_sig.map(|e| e.output);
+
+        let is_infer = match decl.output {
+            hir::Return(ref output) if output.node == hir::TyInfer => true,
+            hir::DefaultReturn(..) => true,
+            _ => false
+        };
+
+        let output_ty = match decl.output {
+            _ if is_infer && expected_ret_ty.is_some() =>
+                expected_ret_ty.unwrap(),
+            _ if is_infer =>
+                ty::FnConverging(self.ty_infer(None, None, None, decl.output.span())),
+            hir::Return(ref output) =>
+                ty::FnConverging(self.ast_ty_to_ty(&rb, &output)),
+            hir::DefaultReturn(..) => bug!(),
+            hir::NoReturn(..) => ty::FnDiverging
+        };
+
+        debug!("ty_of_closure: input_tys={:?}", input_tys);
+        debug!("ty_of_closure: output_ty={:?}", output_ty);
+
+        ty::ClosureTy {
+            unsafety: unsafety,
+            abi: abi,
+            sig: ty::Binder(ty::FnSig {inputs: input_tys,
+                                       output: output_ty,
+                                       variadic: decl.variadic}),
+        }
+    }
+
+    /// Given an existential type like `Foo+'a+Bar`, this routine converts
+    /// the `'a` and `Bar` intos an `ExistentialBounds` struct.
+    /// The `main_trait_refs` argument specifies the `Foo` -- it is absent
+    /// for closures. Eventually this should all be normalized, I think,
+    /// so that there is no "main trait ref" and instead we just have a flat
+    /// list of bounds as the existential type.
+    fn conv_existential_bounds(&self,
+        rscope: &RegionScope,
+        span: Span,
+        principal_trait_ref: ty::PolyTraitRef<'tcx>,
+        projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
+        ast_bounds: &[hir::TyParamBound])
+        -> ty::ExistentialBounds<'tcx>
+    {
+        let partitioned_bounds =
+            partition_bounds(self.tcx(), span, ast_bounds);
+
+        self.conv_existential_bounds_from_partitioned_bounds(
+            rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds)
+    }
+
+    fn conv_ty_poly_trait_ref(&self,
+        rscope: &RegionScope,
+        span: Span,
+        ast_bounds: &[hir::TyParamBound])
+        -> Ty<'tcx>
+    {
+        let mut partitioned_bounds = partition_bounds(self.tcx(), span, &ast_bounds[..]);
+
+        let mut projection_bounds = Vec::new();
+        let main_trait_bound = if !partitioned_bounds.trait_bounds.is_empty() {
+            let trait_bound = partitioned_bounds.trait_bounds.remove(0);
+            self.instantiate_poly_trait_ref(rscope,
+                                            trait_bound,
+                                            None,
+                                            &mut projection_bounds)
+        } else {
+            span_err!(self.tcx().sess, span, E0224,
+                      "at least one non-builtin trait is required for an object type");
+            return self.tcx().types.err;
+        };
+
+        let bounds =
+            self.conv_existential_bounds_from_partitioned_bounds(rscope,
+                                                                 span,
+                                                                 main_trait_bound.clone(),
+                                                                 projection_bounds,
+                                                                 partitioned_bounds);
+
+        self.make_object_type(span, main_trait_bound, bounds)
+    }
+
+    pub fn conv_existential_bounds_from_partitioned_bounds(&self,
+        rscope: &RegionScope,
+        span: Span,
+        principal_trait_ref: ty::PolyTraitRef<'tcx>,
+        projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, // Empty for boxed closures
+        partitioned_bounds: PartitionedBounds)
+        -> ty::ExistentialBounds<'tcx>
+    {
+        let PartitionedBounds { builtin_bounds,
+                                trait_bounds,
+                                region_bounds } =
+            partitioned_bounds;
+
+        if !trait_bounds.is_empty() {
+            let b = &trait_bounds[0];
+            span_err!(self.tcx().sess, b.trait_ref.path.span, E0225,
+                      "only the builtin traits can be used as closure or object bounds");
+        }
+
+        let region_bound =
+            self.compute_object_lifetime_bound(span,
+                                               &region_bounds,
+                                               principal_trait_ref,
+                                               builtin_bounds);
+
+        let region_bound = match region_bound {
+            Some(r) => r,
+            None => {
+                match rscope.object_lifetime_default(span) {
+                    Some(r) => r,
+                    None => {
+                        span_err!(self.tcx().sess, span, E0228,
+                                  "the lifetime bound for this object type cannot be deduced \
+                                   from context; please supply an explicit bound");
+                        ty::ReStatic
+                    }
+                }
+            }
+        };
+
+        debug!("region_bound: {:?}", region_bound);
+
+        ty::ExistentialBounds::new(region_bound, builtin_bounds, projection_bounds)
+    }
+
+    /// Given the bounds on an object, determines what single region bound (if any) we can
+    /// use to summarize this type. The basic idea is that we will use the bound the user
+    /// provided, if they provided one, and otherwise search the supertypes of trait bounds
+    /// for region bounds. It may be that we can derive no bound at all, in which case
+    /// we return `None`.
+    fn compute_object_lifetime_bound(&self,
+        span: Span,
+        explicit_region_bounds: &[&hir::Lifetime],
+        principal_trait_ref: ty::PolyTraitRef<'tcx>,
+        builtin_bounds: ty::BuiltinBounds)
+        -> Option<ty::Region> // if None, use the default
+    {
+        let tcx = self.tcx();
+
+        debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
+               principal_trait_ref={:?}, builtin_bounds={:?})",
+               explicit_region_bounds,
+               principal_trait_ref,
+               builtin_bounds);
+
+        if explicit_region_bounds.len() > 1 {
+            span_err!(tcx.sess, explicit_region_bounds[1].span, E0226,
+                "only a single explicit lifetime bound is permitted");
+        }
+
+        if !explicit_region_bounds.is_empty() {
+            // Explicitly specified region bound. Use that.
+            let r = explicit_region_bounds[0];
+            return Some(ast_region_to_region(tcx, r));
+        }
+
+        if let Err(ErrorReported) =
+                self.ensure_super_predicates(span, principal_trait_ref.def_id()) {
+            return Some(ty::ReStatic);
+        }
+
+        // No explicit region bound specified. Therefore, examine trait
+        // bounds and see if we can derive region bounds from those.
+        let derived_region_bounds =
+            object_region_bounds(tcx, &principal_trait_ref, builtin_bounds);
+
+        // If there are no derived region bounds, then report back that we
+        // can find no region bound. The caller will use the default.
+        if derived_region_bounds.is_empty() {
+            return None;
+        }
+
+        // If any of the derived region bounds are 'static, that is always
+        // the best choice.
+        if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
+            return Some(ty::ReStatic);
+        }
+
+        // Determine whether there is exactly one unique region in the set
+        // of derived region bounds. If so, use that. Otherwise, report an
+        // error.
+        let r = derived_region_bounds[0];
+        if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
+            span_err!(tcx.sess, span, E0227,
+                      "ambiguous lifetime bound, explicit lifetime bound required");
+        }
+        return Some(r);
     }
-    return Some(r);
-}
 }
 
 pub struct PartitionedBounds<'a> {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 899e4f62cc3..d55ca803c64 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -56,765 +56,767 @@ fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: b
 }
 
 impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
-pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
-    let tcx = self.tcx;
+    pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
+        let tcx = self.tcx;
 
-    debug!("check_pat(pat={:?},expected={:?})", pat, expected);
+        debug!("check_pat(pat={:?},expected={:?})", pat, expected);
 
-    match pat.node {
-        PatKind::Wild => {
-            self.write_ty(pat.id, expected);
-        }
-        PatKind::Lit(ref lt) => {
-            self.check_expr(&lt);
-            let expr_ty = self.expr_ty(&lt);
+        match pat.node {
+            PatKind::Wild => {
+                self.write_ty(pat.id, expected);
+            }
+            PatKind::Lit(ref lt) => {
+                self.check_expr(&lt);
+                let expr_ty = self.expr_ty(&lt);
 
-            // Byte string patterns behave the same way as array patterns
-            // They can denote both statically and dynamically sized byte arrays
-            let mut pat_ty = expr_ty;
-            if let hir::ExprLit(ref lt) = lt.node {
-                if let ast::LitKind::ByteStr(_) = lt.node {
-                    let expected_ty = self.structurally_resolved_type(pat.span, expected);
-                    if let ty::TyRef(_, mt) = expected_ty.sty {
-                        if let ty::TySlice(_) = mt.ty.sty {
-                            pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
-                                                     tcx.mk_slice(tcx.types.u8))
+                // Byte string patterns behave the same way as array patterns
+                // They can denote both statically and dynamically sized byte arrays
+                let mut pat_ty = expr_ty;
+                if let hir::ExprLit(ref lt) = lt.node {
+                    if let ast::LitKind::ByteStr(_) = lt.node {
+                        let expected_ty = self.structurally_resolved_type(pat.span, expected);
+                        if let ty::TyRef(_, mt) = expected_ty.sty {
+                            if let ty::TySlice(_) = mt.ty.sty {
+                                pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
+                                                         tcx.mk_slice(tcx.types.u8))
+                            }
                         }
                     }
                 }
+
+                self.write_ty(pat.id, pat_ty);
+
+                // somewhat surprising: in this case, the subtyping
+                // relation goes the opposite way as the other
+                // cases. Actually what we really want is not a subtyping
+                // relation at all but rather that there exists a LUB (so
+                // that they can be compared). However, in practice,
+                // constants are always scalars or strings.  For scalars
+                // subtyping is irrelevant, and for strings `expr_ty` is
+                // type is `&'static str`, so if we say that
+                //
+                //     &'static str <: expected
+                //
+                // that's equivalent to there existing a LUB.
+                self.demand_suptype(pat.span, expected, pat_ty);
             }
+            PatKind::Range(ref begin, ref end) => {
+                self.check_expr(begin);
+                self.check_expr(end);
 
-            self.write_ty(pat.id, pat_ty);
+                let lhs_ty = self.expr_ty(begin);
+                let rhs_ty = self.expr_ty(end);
 
-            // somewhat surprising: in this case, the subtyping
-            // relation goes the opposite way as the other
-            // cases. Actually what we really want is not a subtyping
-            // relation at all but rather that there exists a LUB (so
-            // that they can be compared). However, in practice,
-            // constants are always scalars or strings.  For scalars
-            // subtyping is irrelevant, and for strings `expr_ty` is
-            // type is `&'static str`, so if we say that
-            //
-            //     &'static str <: expected
-            //
-            // that's equivalent to there existing a LUB.
-            self.demand_suptype(pat.span, expected, pat_ty);
-        }
-        PatKind::Range(ref begin, ref end) => {
-            self.check_expr(begin);
-            self.check_expr(end);
+                // Check that both end-points are of numeric or char type.
+                let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char();
+                let lhs_compat = numeric_or_char(lhs_ty);
+                let rhs_compat = numeric_or_char(rhs_ty);
 
-            let lhs_ty = self.expr_ty(begin);
-            let rhs_ty = self.expr_ty(end);
+                if !lhs_compat || !rhs_compat {
+                    let span = if !lhs_compat && !rhs_compat {
+                        pat.span
+                    } else if !lhs_compat {
+                        begin.span
+                    } else {
+                        end.span
+                    };
 
-            // Check that both end-points are of numeric or char type.
-            let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char();
-            let lhs_compat = numeric_or_char(lhs_ty);
-            let rhs_compat = numeric_or_char(rhs_ty);
-
-            if !lhs_compat || !rhs_compat {
-                let span = if !lhs_compat && !rhs_compat {
-                    pat.span
-                } else if !lhs_compat {
-                    begin.span
-                } else {
-                    end.span
-                };
-
-                // Note: spacing here is intentional, we want a space before "start" and "end".
-                span_err!(tcx.sess, span, E0029,
-                          "only char and numeric types are allowed in range patterns\n \
-                           start type: {}\n end type: {}",
-                          self.ty_to_string(lhs_ty),
-                          self.ty_to_string(rhs_ty)
-                );
-                return;
-            }
-
-            // Check that the types of the end-points can be unified.
-            let types_unify = self.require_same_types(pat.span, rhs_ty, lhs_ty,
-                                                      "mismatched types in range");
-
-            // It's ok to return without a message as `require_same_types` prints an error.
-            if !types_unify {
-                return;
-            }
-
-            // Now that we know the types can be unified we find the unified type and use
-            // it to type the entire expression.
-            let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
-
-            self.write_ty(pat.id, common_type);
-
-            // subtyping doesn't matter here, as the value is some kind of scalar
-            self.demand_eqtype(pat.span, expected, lhs_ty);
-        }
-        PatKind::Path(..) | PatKind::Ident(..)
-                if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
-            if let Some(pat_def) = tcx.def_map.borrow().get(&pat.id) {
-                let const_did = pat_def.def_id();
-                let const_scheme = tcx.lookup_item_type(const_did);
-                assert!(const_scheme.generics.is_empty());
-                let const_ty = self.instantiate_type_scheme(pat.span,
-                                                            &Substs::empty(),
-                                                            &const_scheme.ty);
-                self.write_ty(pat.id, const_ty);
-
-                // FIXME(#20489) -- we should limit the types here to scalars or something!
-
-                // As with PatKind::Lit, what we really want here is that there
-                // exist a LUB, but for the cases that can occur, subtype
-                // is good enough.
-                self.demand_suptype(pat.span, expected, const_ty);
-            } else {
-                self.write_error(pat.id);
-            }
-        }
-        PatKind::Ident(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map.borrow(), pat) => {
-            let typ = self.local_ty(pat.span, pat.id);
-            match bm {
-                hir::BindByRef(mutbl) => {
-                    // if the binding is like
-                    //    ref x | ref const x | ref mut x
-                    // then `x` is assigned a value of type `&M T` where M is the mutability
-                    // and T is the expected type.
-                    let region_var = self.next_region_var(infer::PatternRegion(pat.span));
-                    let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl };
-                    let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt);
-
-                    // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
-                    // required. However, we use equality, which is stronger. See (*) for
-                    // an explanation.
-                    self.demand_eqtype(pat.span, region_ty, typ);
-                }
-                // otherwise the type of x is the expected type T
-                hir::BindByValue(_) => {
-                    // As above, `T <: typeof(x)` is required but we
-                    // use equality, see (*) below.
-                    self.demand_eqtype(pat.span, expected, typ);
-                }
-            }
-
-            self.write_ty(pat.id, typ);
-
-            // if there are multiple arms, make sure they all agree on
-            // what the type of the binding `x` ought to be
-            if let Some(&canon_id) = self.map.get(&path.node.name) {
-                if canon_id != pat.id {
-                    let ct = self.local_ty(pat.span, canon_id);
-                    self.demand_eqtype(pat.span, ct, typ);
-                }
-
-                if let Some(ref p) = *sub {
-                    self.check_pat(&p, expected);
-                }
-            }
-        }
-        PatKind::Ident(_, ref path, _) => {
-            let path = hir::Path::from_ident(path.span, path.node);
-            self.check_pat_enum(pat, &path, Some(&[]), expected, false);
-        }
-        PatKind::TupleStruct(ref path, ref subpats) => {
-            self.check_pat_enum(pat, path, subpats.as_ref().map(|v| &v[..]), expected, true);
-        }
-        PatKind::Path(ref path) => {
-            self.check_pat_enum(pat, path, Some(&[]), expected, false);
-        }
-        PatKind::QPath(ref qself, ref path) => {
-            let self_ty = self.to_ty(&qself.ty);
-            let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
-                if d.base_def == Def::Err {
-                    self.set_tainted_by_errors();
-                    self.write_error(pat.id);
+                    // Note: spacing here is intentional, we want a space before "start" and "end".
+                    span_err!(tcx.sess, span, E0029,
+                              "only char and numeric types are allowed in range patterns\n \
+                               start type: {}\n end type: {}",
+                              self.ty_to_string(lhs_ty),
+                              self.ty_to_string(rhs_ty)
+                    );
                     return;
                 }
-                d
-            } else if qself.position == 0 {
-                // This is just a sentinel for finish_resolving_def_to_ty.
-                let sentinel = self.tcx.map.local_def_id(ast::CRATE_NODE_ID);
-                def::PathResolution {
-                    base_def: Def::Mod(sentinel),
-                    depth: path.segments.len()
+
+                // Check that the types of the end-points can be unified.
+                let types_unify = self.require_same_types(pat.span, rhs_ty, lhs_ty,
+                                                          "mismatched types in range");
+
+                // It's ok to return without a message as `require_same_types` prints an error.
+                if !types_unify {
+                    return;
                 }
-            } else {
-                debug!("unbound path {:?}", pat);
-                self.write_error(pat.id);
-                return;
-            };
-            if let Some((opt_ty, segments, def)) =
-                    self.resolve_ty_and_def_ufcs(path_res, Some(self_ty),
-                                                 path, pat.span, pat.id) {
-                if self.check_assoc_item_is_const(def, pat.span) {
-                    let scheme = tcx.lookup_item_type(def.def_id());
-                    let predicates = tcx.lookup_predicates(def.def_id());
-                    self.instantiate_path(segments, scheme, &predicates,
-                                          opt_ty, def, pat.span, pat.id);
-                    let const_ty = self.node_ty(pat.id);
+
+                // Now that we know the types can be unified we find the unified type and use
+                // it to type the entire expression.
+                let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
+
+                self.write_ty(pat.id, common_type);
+
+                // subtyping doesn't matter here, as the value is some kind of scalar
+                self.demand_eqtype(pat.span, expected, lhs_ty);
+            }
+            PatKind::Path(..) | PatKind::Ident(..)
+                    if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
+                if let Some(pat_def) = tcx.def_map.borrow().get(&pat.id) {
+                    let const_did = pat_def.def_id();
+                    let const_scheme = tcx.lookup_item_type(const_did);
+                    assert!(const_scheme.generics.is_empty());
+                    let const_ty = self.instantiate_type_scheme(pat.span,
+                                                                &Substs::empty(),
+                                                                &const_scheme.ty);
+                    self.write_ty(pat.id, const_ty);
+
+                    // FIXME(#20489) -- we should limit the types here to scalars or something!
+
+                    // As with PatKind::Lit, what we really want here is that there
+                    // exist a LUB, but for the cases that can occur, subtype
+                    // is good enough.
                     self.demand_suptype(pat.span, expected, const_ty);
                 } else {
-                    self.write_error(pat.id)
+                    self.write_error(pat.id);
                 }
             }
-        }
-        PatKind::Struct(ref path, ref fields, etc) => {
-            self.check_pat_struct(pat, path, fields, etc, expected);
-        }
-        PatKind::Tup(ref elements) => {
-            let element_tys: Vec<_> =
-                (0..elements.len()).map(|_| self.next_ty_var()).collect();
-            let pat_ty = tcx.mk_tup(element_tys.clone());
-            self.write_ty(pat.id, pat_ty);
-            self.demand_eqtype(pat.span, expected, pat_ty);
-            for (element_pat, element_ty) in elements.iter().zip(element_tys) {
-                self.check_pat(&element_pat, element_ty);
-            }
-        }
-        PatKind::Box(ref inner) => {
-            let inner_ty = self.next_ty_var();
-            let uniq_ty = tcx.mk_box(inner_ty);
+            PatKind::Ident(bm, ref path, ref sub)
+                    if pat_is_binding(&tcx.def_map.borrow(), pat) => {
+                let typ = self.local_ty(pat.span, pat.id);
+                match bm {
+                    hir::BindByRef(mutbl) => {
+                        // if the binding is like
+                        //    ref x | ref const x | ref mut x
+                        // then `x` is assigned a value of type `&M T` where M is the mutability
+                        // and T is the expected type.
+                        let region_var = self.next_region_var(infer::PatternRegion(pat.span));
+                        let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl };
+                        let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt);
 
-            if self.check_dereferencable(pat.span, expected, &inner) {
-                // Here, `demand::subtype` is good enough, but I don't
-                // think any errors can be introduced by using
-                // `demand::eqtype`.
-                self.demand_eqtype(pat.span, expected, uniq_ty);
-                self.write_ty(pat.id, uniq_ty);
-                self.check_pat(&inner, inner_ty);
-            } else {
-                self.write_error(pat.id);
-                self.check_pat(&inner, tcx.types.err);
+                        // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
+                        // required. However, we use equality, which is stronger. See (*) for
+                        // an explanation.
+                        self.demand_eqtype(pat.span, region_ty, typ);
+                    }
+                    // otherwise the type of x is the expected type T
+                    hir::BindByValue(_) => {
+                        // As above, `T <: typeof(x)` is required but we
+                        // use equality, see (*) below.
+                        self.demand_eqtype(pat.span, expected, typ);
+                    }
+                }
+
+                self.write_ty(pat.id, typ);
+
+                // if there are multiple arms, make sure they all agree on
+                // what the type of the binding `x` ought to be
+                if let Some(&canon_id) = self.map.get(&path.node.name) {
+                    if canon_id != pat.id {
+                        let ct = self.local_ty(pat.span, canon_id);
+                        self.demand_eqtype(pat.span, ct, typ);
+                    }
+
+                    if let Some(ref p) = *sub {
+                        self.check_pat(&p, expected);
+                    }
+                }
             }
-        }
-        PatKind::Ref(ref inner, mutbl) => {
-            let expected = self.shallow_resolve(expected);
-            if self.check_dereferencable(pat.span, expected, &inner) {
+            PatKind::Ident(_, ref path, _) => {
+                let path = hir::Path::from_ident(path.span, path.node);
+                self.check_pat_enum(pat, &path, Some(&[]), expected, false);
+            }
+            PatKind::TupleStruct(ref path, ref subpats) => {
+                self.check_pat_enum(pat, path, subpats.as_ref().map(|v| &v[..]), expected, true);
+            }
+            PatKind::Path(ref path) => {
+                self.check_pat_enum(pat, path, Some(&[]), expected, false);
+            }
+            PatKind::QPath(ref qself, ref path) => {
+                let self_ty = self.to_ty(&qself.ty);
+                let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
+                    if d.base_def == Def::Err {
+                        self.set_tainted_by_errors();
+                        self.write_error(pat.id);
+                        return;
+                    }
+                    d
+                } else if qself.position == 0 {
+                    // This is just a sentinel for finish_resolving_def_to_ty.
+                    let sentinel = self.tcx.map.local_def_id(ast::CRATE_NODE_ID);
+                    def::PathResolution {
+                        base_def: Def::Mod(sentinel),
+                        depth: path.segments.len()
+                    }
+                } else {
+                    debug!("unbound path {:?}", pat);
+                    self.write_error(pat.id);
+                    return;
+                };
+                if let Some((opt_ty, segments, def)) =
+                        self.resolve_ty_and_def_ufcs(path_res, Some(self_ty),
+                                                     path, pat.span, pat.id) {
+                    if self.check_assoc_item_is_const(def, pat.span) {
+                        let scheme = tcx.lookup_item_type(def.def_id());
+                        let predicates = tcx.lookup_predicates(def.def_id());
+                        self.instantiate_path(segments, scheme, &predicates,
+                                              opt_ty, def, pat.span, pat.id);
+                        let const_ty = self.node_ty(pat.id);
+                        self.demand_suptype(pat.span, expected, const_ty);
+                    } else {
+                        self.write_error(pat.id)
+                    }
+                }
+            }
+            PatKind::Struct(ref path, ref fields, etc) => {
+                self.check_pat_struct(pat, path, fields, etc, expected);
+            }
+            PatKind::Tup(ref elements) => {
+                let element_tys: Vec<_> =
+                    (0..elements.len()).map(|_| self.next_ty_var()).collect();
+                let pat_ty = tcx.mk_tup(element_tys.clone());
+                self.write_ty(pat.id, pat_ty);
+                self.demand_eqtype(pat.span, expected, pat_ty);
+                for (element_pat, element_ty) in elements.iter().zip(element_tys) {
+                    self.check_pat(&element_pat, element_ty);
+                }
+            }
+            PatKind::Box(ref inner) => {
+                let inner_ty = self.next_ty_var();
+                let uniq_ty = tcx.mk_box(inner_ty);
+
+                if self.check_dereferencable(pat.span, expected, &inner) {
+                    // Here, `demand::subtype` is good enough, but I don't
+                    // think any errors can be introduced by using
+                    // `demand::eqtype`.
+                    self.demand_eqtype(pat.span, expected, uniq_ty);
+                    self.write_ty(pat.id, uniq_ty);
+                    self.check_pat(&inner, inner_ty);
+                } else {
+                    self.write_error(pat.id);
+                    self.check_pat(&inner, tcx.types.err);
+                }
+            }
+            PatKind::Ref(ref inner, mutbl) => {
+                let expected = self.shallow_resolve(expected);
+                if self.check_dereferencable(pat.span, expected, &inner) {
+                    // `demand::subtype` would be good enough, but using
+                    // `eqtype` turns out to be equally general. See (*)
+                    // below for details.
+
+                    // Take region, inner-type from expected type if we
+                    // can, to avoid creating needless variables.  This
+                    // also helps with the bad interactions of the given
+                    // hack detailed in (*) below.
+                    let (rptr_ty, inner_ty) = match expected.sty {
+                        ty::TyRef(_, mt) if mt.mutbl == mutbl => {
+                            (expected, mt.ty)
+                        }
+                        _ => {
+                            let inner_ty = self.next_ty_var();
+                            let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
+                            let region = self.next_region_var(infer::PatternRegion(pat.span));
+                            let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
+                            self.demand_eqtype(pat.span, expected, rptr_ty);
+                            (rptr_ty, inner_ty)
+                        }
+                    };
+
+                    self.write_ty(pat.id, rptr_ty);
+                    self.check_pat(&inner, inner_ty);
+                } else {
+                    self.write_error(pat.id);
+                    self.check_pat(&inner, tcx.types.err);
+                }
+            }
+            PatKind::Vec(ref before, ref slice, ref after) => {
+                let expected_ty = self.structurally_resolved_type(pat.span, expected);
+                let inner_ty = self.next_ty_var();
+                let pat_ty = match expected_ty.sty {
+                    ty::TyArray(_, size) => tcx.mk_array(inner_ty, {
+                        let min_len = before.len() + after.len();
+                        match *slice {
+                            Some(_) => cmp::max(min_len, size),
+                            None => min_len
+                        }
+                    }),
+                    _ => {
+                        let region = self.next_region_var(infer::PatternRegion(pat.span));
+                        tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
+                            ty: tcx.mk_slice(inner_ty),
+                            mutbl: expected_ty.builtin_deref(true, ty::NoPreference)
+                                              .map_or(hir::MutImmutable, |mt| mt.mutbl)
+                        })
+                    }
+                };
+
+                self.write_ty(pat.id, pat_ty);
+
                 // `demand::subtype` would be good enough, but using
                 // `eqtype` turns out to be equally general. See (*)
                 // below for details.
+                self.demand_eqtype(pat.span, expected, pat_ty);
 
-                // Take region, inner-type from expected type if we
-                // can, to avoid creating needless variables.  This
-                // also helps with the bad interactions of the given
-                // hack detailed in (*) below.
-                let (rptr_ty, inner_ty) = match expected.sty {
-                    ty::TyRef(_, mt) if mt.mutbl == mutbl => {
-                        (expected, mt.ty)
-                    }
-                    _ => {
-                        let inner_ty = self.next_ty_var();
-                        let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
-                        let region = self.next_region_var(infer::PatternRegion(pat.span));
-                        let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
-                        self.demand_eqtype(pat.span, expected, rptr_ty);
-                        (rptr_ty, inner_ty)
-                    }
-                };
-
-                self.write_ty(pat.id, rptr_ty);
-                self.check_pat(&inner, inner_ty);
-            } else {
-                self.write_error(pat.id);
-                self.check_pat(&inner, tcx.types.err);
-            }
-        }
-        PatKind::Vec(ref before, ref slice, ref after) => {
-            let expected_ty = self.structurally_resolved_type(pat.span, expected);
-            let inner_ty = self.next_ty_var();
-            let pat_ty = match expected_ty.sty {
-                ty::TyArray(_, size) => tcx.mk_array(inner_ty, {
-                    let min_len = before.len() + after.len();
-                    match *slice {
-                        Some(_) => cmp::max(min_len, size),
-                        None => min_len
-                    }
-                }),
-                _ => {
-                    let region = self.next_region_var(infer::PatternRegion(pat.span));
-                    tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
-                        ty: tcx.mk_slice(inner_ty),
-                        mutbl: expected_ty.builtin_deref(true, ty::NoPreference).map(|mt| mt.mutbl)
-                                                              .unwrap_or(hir::MutImmutable)
-                    })
+                for elt in before {
+                    self.check_pat(&elt, inner_ty);
                 }
-            };
+                if let Some(ref slice) = *slice {
+                    let region = self.next_region_var(infer::PatternRegion(pat.span));
+                    let mutbl = expected_ty.builtin_deref(true, ty::NoPreference)
+                        .map_or(hir::MutImmutable, |mt| mt.mutbl);
 
-            self.write_ty(pat.id, pat_ty);
-
-            // `demand::subtype` would be good enough, but using
-            // `eqtype` turns out to be equally general. See (*)
-            // below for details.
-            self.demand_eqtype(pat.span, expected, pat_ty);
-
-            for elt in before {
-                self.check_pat(&elt, inner_ty);
-            }
-            if let Some(ref slice) = *slice {
-                let region = self.next_region_var(infer::PatternRegion(pat.span));
-                let mutbl = expected_ty.builtin_deref(true, ty::NoPreference)
-                    .map_or(hir::MutImmutable, |mt| mt.mutbl);
-
-                let slice_ty = tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
-                    ty: tcx.mk_slice(inner_ty),
-                    mutbl: mutbl
-                });
-                self.check_pat(&slice, slice_ty);
-            }
-            for elt in after {
-                self.check_pat(&elt, inner_ty);
+                    let slice_ty = tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
+                        ty: tcx.mk_slice(inner_ty),
+                        mutbl: mutbl
+                    });
+                    self.check_pat(&slice, slice_ty);
+                }
+                for elt in after {
+                    self.check_pat(&elt, inner_ty);
+                }
             }
         }
+
+
+        // (*) In most of the cases above (literals and constants being
+        // the exception), we relate types using strict equality, evewn
+        // though subtyping would be sufficient. There are a few reasons
+        // for this, some of which are fairly subtle and which cost me
+        // (nmatsakis) an hour or two debugging to remember, so I thought
+        // I'd write them down this time.
+        //
+        // 1. There is no loss of expressiveness here, though it does
+        // cause some inconvenience. What we are saying is that the type
+        // of `x` becomes *exactly* what is expected. This can cause unnecessary
+        // errors in some cases, such as this one:
+        // it will cause errors in a case like this:
+        //
+        // ```
+        // fn foo<'x>(x: &'x int) {
+        //    let a = 1;
+        //    let mut z = x;
+        //    z = &a;
+        // }
+        // ```
+        //
+        // The reason we might get an error is that `z` might be
+        // assigned a type like `&'x int`, and then we would have
+        // a problem when we try to assign `&a` to `z`, because
+        // the lifetime of `&a` (i.e., the enclosing block) is
+        // shorter than `'x`.
+        //
+        // HOWEVER, this code works fine. The reason is that the
+        // expected type here is whatever type the user wrote, not
+        // the initializer's type. In this case the user wrote
+        // nothing, so we are going to create a type variable `Z`.
+        // Then we will assign the type of the initializer (`&'x
+        // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we
+        // will instantiate `Z` as a type `&'0 int` where `'0` is
+        // a fresh region variable, with the constraint that `'x :
+        // '0`.  So basically we're all set.
+        //
+        // Note that there are two tests to check that this remains true
+        // (`regions-reassign-{match,let}-bound-pointer.rs`).
+        //
+        // 2. Things go horribly wrong if we use subtype. The reason for
+        // THIS is a fairly subtle case involving bound regions. See the
+        // `givens` field in `region_inference`, as well as the test
+        // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
+        // for details. Short version is that we must sometimes detect
+        // relationships between specific region variables and regions
+        // bound in a closure signature, and that detection gets thrown
+        // off when we substitute fresh region variables here to enable
+        // subtyping.
     }
 
-
-    // (*) In most of the cases above (literals and constants being
-    // the exception), we relate types using strict equality, evewn
-    // though subtyping would be sufficient. There are a few reasons
-    // for this, some of which are fairly subtle and which cost me
-    // (nmatsakis) an hour or two debugging to remember, so I thought
-    // I'd write them down this time.
-    //
-    // 1. There is no loss of expressiveness here, though it does
-    // cause some inconvenience. What we are saying is that the type
-    // of `x` becomes *exactly* what is expected. This can cause unnecessary
-    // errors in some cases, such as this one:
-    // it will cause errors in a case like this:
-    //
-    // ```
-    // fn foo<'x>(x: &'x int) {
-    //    let a = 1;
-    //    let mut z = x;
-    //    z = &a;
-    // }
-    // ```
-    //
-    // The reason we might get an error is that `z` might be
-    // assigned a type like `&'x int`, and then we would have
-    // a problem when we try to assign `&a` to `z`, because
-    // the lifetime of `&a` (i.e., the enclosing block) is
-    // shorter than `'x`.
-    //
-    // HOWEVER, this code works fine. The reason is that the
-    // expected type here is whatever type the user wrote, not
-    // the initializer's type. In this case the user wrote
-    // nothing, so we are going to create a type variable `Z`.
-    // Then we will assign the type of the initializer (`&'x
-    // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we
-    // will instantiate `Z` as a type `&'0 int` where `'0` is
-    // a fresh region variable, with the constraint that `'x :
-    // '0`.  So basically we're all set.
-    //
-    // Note that there are two tests to check that this remains true
-    // (`regions-reassign-{match,let}-bound-pointer.rs`).
-    //
-    // 2. Things go horribly wrong if we use subtype. The reason for
-    // THIS is a fairly subtle case involving bound regions. See the
-    // `givens` field in `region_inference`, as well as the test
-    // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
-    // for details. Short version is that we must sometimes detect
-    // relationships between specific region variables and regions
-    // bound in a closure signature, and that detection gets thrown
-    // off when we substitute fresh region variables here to enable
-    // subtyping.
-}
-
-fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool {
-    match def {
-        Def::AssociatedConst(..) => true,
-        Def::Method(..) => {
-            span_err!(self.tcx.sess, span, E0327,
-                      "associated items in match patterns must be constants");
-            false
-        }
-        _ => {
-            span_bug!(span, "non-associated item in check_assoc_item_is_const");
-        }
-    }
-}
-
-pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
-    let tcx = self.tcx;
-    if pat_is_binding(&tcx.def_map.borrow(), inner) {
-        let expected = self.shallow_resolve(expected);
-        expected.builtin_deref(true, ty::NoPreference).map_or(true, |mt| match mt.ty.sty {
-            ty::TyTrait(_) => {
-                // This is "x = SomeTrait" being reduced from
-                // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
-                span_err!(tcx.sess, span, E0033,
-                          "type `{}` cannot be dereferenced",
-                          self.ty_to_string(expected));
+    fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool {
+        match def {
+            Def::AssociatedConst(..) => true,
+            Def::Method(..) => {
+                span_err!(self.tcx.sess, span, E0327,
+                          "associated items in match patterns must be constants");
                 false
             }
-            _ => true
-        })
-    } else {
-        true
+            _ => {
+                span_bug!(span, "non-associated item in check_assoc_item_is_const");
+            }
+        }
+    }
+
+    pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
+        let tcx = self.tcx;
+        if pat_is_binding(&tcx.def_map.borrow(), inner) {
+            let expected = self.shallow_resolve(expected);
+            expected.builtin_deref(true, ty::NoPreference).map_or(true, |mt| match mt.ty.sty {
+                ty::TyTrait(_) => {
+                    // This is "x = SomeTrait" being reduced from
+                    // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
+                    span_err!(tcx.sess, span, E0033,
+                              "type `{}` cannot be dereferenced",
+                              self.ty_to_string(expected));
+                    false
+                }
+                _ => true
+            })
+        } else {
+            true
+        }
     }
-}
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-pub fn check_match(&self,
-                   expr: &'gcx hir::Expr,
-                   discrim: &'gcx hir::Expr,
-                   arms: &'gcx [hir::Arm],
-                   expected: Expectation<'tcx>,
-                   match_src: hir::MatchSource) {
-    let tcx = self.tcx;
+    pub fn check_match(&self,
+                       expr: &'gcx hir::Expr,
+                       discrim: &'gcx hir::Expr,
+                       arms: &'gcx [hir::Arm],
+                       expected: Expectation<'tcx>,
+                       match_src: hir::MatchSource) {
+        let tcx = self.tcx;
 
-    // Not entirely obvious: if matches may create ref bindings, we
-    // want to use the *precise* type of the discriminant, *not* some
-    // supertype, as the "discriminant type" (issue #23116).
-    let contains_ref_bindings = arms.iter()
-                                    .filter_map(|a| tcx.arm_contains_ref_binding(a))
-                                    .max_by_key(|m| match *m {
-                                        hir::MutMutable => 1,
-                                        hir::MutImmutable => 0,
-                                    });
-    let discrim_ty;
-    if let Some(m) = contains_ref_bindings {
-        self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
-        discrim_ty = self.expr_ty(discrim);
-    } else {
-        // ...but otherwise we want to use any supertype of the
-        // discriminant. This is sort of a workaround, see note (*) in
-        // `check_pat` for some details.
-        discrim_ty = self.next_ty_var();
-        self.check_expr_has_type(discrim, discrim_ty);
-    };
-
-    // Typecheck the patterns first, so that we get types for all the
-    // bindings.
-    for arm in arms {
-        let pcx = PatCtxt {
-            fcx: self,
-            map: pat_id_map(&tcx.def_map, &arm.pats[0]),
-        };
-        for p in &arm.pats {
-            pcx.check_pat(&p, discrim_ty);
-        }
-    }
-
-    // Now typecheck the blocks.
-    //
-    // The result of the match is the common supertype of all the
-    // arms. Start out the value as bottom, since it's the, well,
-    // bottom the type lattice, and we'll be moving up the lattice as
-    // we process each arm. (Note that any match with 0 arms is matching
-    // on any empty type and is therefore unreachable; should the flow
-    // of execution reach it, we will panic, so bottom is an appropriate
-    // type in that case)
-    let expected = expected.adjust_for_branches(self);
-    let mut result_ty = self.next_diverging_ty_var();
-    let coerce_first = match expected {
-        // We don't coerce to `()` so that if the match expression is a
-        // statement it's branches can have any consistent type. That allows
-        // us to give better error messages (pointing to a usually better
-        // arm for inconsistent arms or to the whole match when a `()` type
-        // is required).
-        Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => {
-            ety
-        }
-        _ => result_ty
-    };
-    for (i, arm) in arms.iter().enumerate() {
-        if let Some(ref e) = arm.guard {
-            self.check_expr_has_type(e, tcx.types.bool);
-        }
-        self.check_expr_with_expectation(&arm.body, expected);
-        let arm_ty = self.expr_ty(&arm.body);
-
-        if result_ty.references_error() || arm_ty.references_error() {
-            result_ty = tcx.types.err;
-            continue;
-        }
-
-        // Handle the fallback arm of a desugared if-let like a missing else.
-        let is_if_let_fallback = match match_src {
-            hir::MatchSource::IfLetDesugar { contains_else_clause: false } => {
-                i == arms.len() - 1 && arm_ty.is_nil()
-            }
-            _ => false
-        };
-
-        let origin = if is_if_let_fallback {
-            TypeOrigin::IfExpressionWithNoElse(expr.span)
+        // Not entirely obvious: if matches may create ref bindings, we
+        // want to use the *precise* type of the discriminant, *not* some
+        // supertype, as the "discriminant type" (issue #23116).
+        let contains_ref_bindings = arms.iter()
+                                        .filter_map(|a| tcx.arm_contains_ref_binding(a))
+                                        .max_by_key(|m| match *m {
+                                            hir::MutMutable => 1,
+                                            hir::MutImmutable => 0,
+                                        });
+        let discrim_ty;
+        if let Some(m) = contains_ref_bindings {
+            self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
+            discrim_ty = self.expr_ty(discrim);
         } else {
-            TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src)
+            // ...but otherwise we want to use any supertype of the
+            // discriminant. This is sort of a workaround, see note (*) in
+            // `check_pat` for some details.
+            discrim_ty = self.next_ty_var();
+            self.check_expr_has_type(discrim, discrim_ty);
         };
 
-        let result = if is_if_let_fallback {
-            self.eq_types(true, origin, arm_ty, result_ty)
-                .map(|InferOk { obligations, .. }| {
-                    // FIXME(#32730) propagate obligations
-                    assert!(obligations.is_empty());
-                    arm_ty
-                })
-        } else if i == 0 {
-            // Special-case the first arm, as it has no "previous expressions".
-            self.try_coerce(&arm.body, coerce_first)
-        } else {
-            let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
-            self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body)
-        };
-
-        result_ty = match result {
-            Ok(ty) => ty,
-            Err(e) => {
-                let (expected, found) = if is_if_let_fallback {
-                    (arm_ty, result_ty)
-                } else {
-                    (result_ty, arm_ty)
-                };
-                self.report_mismatched_types(origin, expected, found, e);
-                self.tcx.types.err
+        // Typecheck the patterns first, so that we get types for all the
+        // bindings.
+        for arm in arms {
+            let pcx = PatCtxt {
+                fcx: self,
+                map: pat_id_map(&tcx.def_map, &arm.pats[0]),
+            };
+            for p in &arm.pats {
+                pcx.check_pat(&p, discrim_ty);
             }
-        };
-    }
+        }
 
-    self.write_ty(expr.id, result_ty);
-}
+        // Now typecheck the blocks.
+        //
+        // The result of the match is the common supertype of all the
+        // arms. Start out the value as bottom, since it's the, well,
+        // bottom the type lattice, and we'll be moving up the lattice as
+        // we process each arm. (Note that any match with 0 arms is matching
+        // on any empty type and is therefore unreachable; should the flow
+        // of execution reach it, we will panic, so bottom is an appropriate
+        // type in that case)
+        let expected = expected.adjust_for_branches(self);
+        let mut result_ty = self.next_diverging_ty_var();
+        let coerce_first = match expected {
+            // We don't coerce to `()` so that if the match expression is a
+            // statement it's branches can have any consistent type. That allows
+            // us to give better error messages (pointing to a usually better
+            // arm for inconsistent arms or to the whole match when a `()` type
+            // is required).
+            Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => {
+                ety
+            }
+            _ => result_ty
+        };
+        for (i, arm) in arms.iter().enumerate() {
+            if let Some(ref e) = arm.guard {
+                self.check_expr_has_type(e, tcx.types.bool);
+            }
+            self.check_expr_with_expectation(&arm.body, expected);
+            let arm_ty = self.expr_ty(&arm.body);
+
+            if result_ty.references_error() || arm_ty.references_error() {
+                result_ty = tcx.types.err;
+                continue;
+            }
+
+            // Handle the fallback arm of a desugared if-let like a missing else.
+            let is_if_let_fallback = match match_src {
+                hir::MatchSource::IfLetDesugar { contains_else_clause: false } => {
+                    i == arms.len() - 1 && arm_ty.is_nil()
+                }
+                _ => false
+            };
+
+            let origin = if is_if_let_fallback {
+                TypeOrigin::IfExpressionWithNoElse(expr.span)
+            } else {
+                TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src)
+            };
+
+            let result = if is_if_let_fallback {
+                self.eq_types(true, origin, arm_ty, result_ty)
+                    .map(|InferOk { obligations, .. }| {
+                        // FIXME(#32730) propagate obligations
+                        assert!(obligations.is_empty());
+                        arm_ty
+                    })
+            } else if i == 0 {
+                // Special-case the first arm, as it has no "previous expressions".
+                self.try_coerce(&arm.body, coerce_first)
+            } else {
+                let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
+                self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body)
+            };
+
+            result_ty = match result {
+                Ok(ty) => ty,
+                Err(e) => {
+                    let (expected, found) = if is_if_let_fallback {
+                        (arm_ty, result_ty)
+                    } else {
+                        (result_ty, arm_ty)
+                    };
+                    self.report_mismatched_types(origin, expected, found, e);
+                    self.tcx.types.err
+                }
+            };
+        }
+
+        self.write_ty(expr.id, result_ty);
+    }
 }
 
 impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
-pub fn check_pat_struct(&self, pat: &'gcx hir::Pat,
-                        path: &hir::Path, fields: &'gcx [Spanned<hir::FieldPat>],
-                        etc: bool, expected: Ty<'tcx>) {
-    let tcx = self.tcx;
+    pub fn check_pat_struct(&self, pat: &'gcx hir::Pat,
+                            path: &hir::Path, fields: &'gcx [Spanned<hir::FieldPat>],
+                            etc: bool, expected: Ty<'tcx>) {
+        let tcx = self.tcx;
 
-    let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
-    let variant = match self.def_struct_variant(def, path.span) {
-        Some((_, variant)) => variant,
-        None => {
-            let name = pprust::path_to_string(path);
-            span_err!(tcx.sess, pat.span, E0163,
-                      "`{}` does not name a struct or a struct variant", name);
-            self.write_error(pat.id);
+        let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
+        let variant = match self.def_struct_variant(def, path.span) {
+            Some((_, variant)) => variant,
+            None => {
+                let name = pprust::path_to_string(path);
+                span_err!(tcx.sess, pat.span, E0163,
+                          "`{}` does not name a struct or a struct variant", name);
+                self.write_error(pat.id);
 
-            for field in fields {
-                self.check_pat(&field.node.pat, tcx.types.err);
+                for field in fields {
+                    self.check_pat(&field.node.pat, tcx.types.err);
+                }
+                return;
             }
+        };
+
+        let pat_ty = self.instantiate_type(def.def_id(), path);
+        let item_substs = match pat_ty.sty {
+            ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
+            _ => span_bug!(pat.span, "struct variant is not an ADT")
+        };
+        self.demand_eqtype(pat.span, expected, pat_ty);
+        self.check_struct_pat_fields(pat.span, fields, variant, &item_substs, etc);
+
+        self.write_ty(pat.id, pat_ty);
+        self.write_substs(pat.id, ty::ItemSubsts {
+            substs: item_substs
+        });
+    }
+
+    fn check_pat_enum(&self,
+                      pat: &hir::Pat,
+                      path: &hir::Path,
+                      subpats: Option<&'gcx [P<hir::Pat>]>,
+                      expected: Ty<'tcx>,
+                      is_tuple_struct_pat: bool)
+    {
+        // Typecheck the path.
+        let tcx = self.tcx;
+
+        let path_res = match tcx.def_map.borrow().get(&pat.id) {
+            Some(&path_res) if path_res.base_def != Def::Err => path_res,
+            _ => {
+                self.set_tainted_by_errors();
+                self.write_error(pat.id);
+
+                if let Some(subpats) = subpats {
+                    for pat in subpats {
+                        self.check_pat(&pat, tcx.types.err);
+                    }
+                }
+
+                return;
+            }
+        };
+
+        let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res,
+                                                                         None, path,
+                                                                         pat.span, pat.id) {
+            Some(resolution) => resolution,
+            // Error handling done inside resolve_ty_and_def_ufcs, so if
+            // resolution fails just return.
+            None => {return;}
+        };
+
+        // Items that were partially resolved before should have been resolved to
+        // associated constants (i.e. not methods).
+        if path_res.depth != 0 && !self.check_assoc_item_is_const(def, pat.span) {
+            self.write_error(pat.id);
             return;
         }
-    };
 
-    let pat_ty = self.instantiate_type(def.def_id(), path);
-    let item_substs = match pat_ty.sty {
-        ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
-        _ => span_bug!(pat.span, "struct variant is not an ADT")
-    };
-    self.demand_eqtype(pat.span, expected, pat_ty);
-    self.check_struct_pat_fields(pat.span, fields, variant, &item_substs, etc);
+        let enum_def = def.variant_def_ids()
+            .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
 
-    self.write_ty(pat.id, pat_ty);
-    self.write_substs(pat.id, ty::ItemSubsts {
-        substs: item_substs
-    });
-}
+        let ctor_scheme = tcx.lookup_item_type(enum_def);
+        let ctor_predicates = tcx.lookup_predicates(enum_def);
+        let path_scheme = if ctor_scheme.ty.is_fn() {
+            let fn_ret = tcx.no_late_bound_regions(&ctor_scheme.ty.fn_ret()).unwrap();
+            ty::TypeScheme {
+                ty: fn_ret.unwrap(),
+                generics: ctor_scheme.generics,
+            }
+        } else {
+            ctor_scheme
+        };
+        self.instantiate_path(segments, path_scheme, &ctor_predicates,
+                              opt_ty, def, pat.span, pat.id);
 
-fn check_pat_enum(&self,
-                  pat: &hir::Pat,
-                  path: &hir::Path,
-                  subpats: Option<&'gcx [P<hir::Pat>]>,
-                  expected: Ty<'tcx>,
-                  is_tuple_struct_pat: bool)
-{
-    // Typecheck the path.
-    let tcx = self.tcx;
-
-    let path_res = match tcx.def_map.borrow().get(&pat.id) {
-        Some(&path_res) if path_res.base_def != Def::Err => path_res,
-        _ => {
-            self.set_tainted_by_errors();
+        let report_bad_struct_kind = |is_warning| {
+            bad_struct_kind_err(tcx.sess, pat, path, is_warning);
+            if is_warning { return; }
             self.write_error(pat.id);
-
             if let Some(subpats) = subpats {
                 for pat in subpats {
                     self.check_pat(&pat, tcx.types.err);
                 }
             }
+        };
 
+        // If we didn't have a fully resolved path to start with, we had an
+        // associated const, and we should quit now, since the rest of this
+        // function uses checks specific to structs and enums.
+        if path_res.depth != 0 {
+            if is_tuple_struct_pat {
+                report_bad_struct_kind(false);
+            } else {
+                let pat_ty = self.node_ty(pat.id);
+                self.demand_suptype(pat.span, expected, pat_ty);
+            }
             return;
         }
-    };
 
-    let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res,
-                                                                     None, path,
-                                                                     pat.span, pat.id) {
-        Some(resolution) => resolution,
-        // Error handling done inside resolve_ty_and_def_ufcs, so if
-        // resolution fails just return.
-        None => {return;}
-    };
+        let pat_ty = self.node_ty(pat.id);
+        self.demand_eqtype(pat.span, expected, pat_ty);
 
-    // Items that were partially resolved before should have been resolved to
-    // associated constants (i.e. not methods).
-    if path_res.depth != 0 && !self.check_assoc_item_is_const(def, pat.span) {
-        self.write_error(pat.id);
-        return;
-    }
-
-    let enum_def = def.variant_def_ids()
-        .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
-
-    let ctor_scheme = tcx.lookup_item_type(enum_def);
-    let ctor_predicates = tcx.lookup_predicates(enum_def);
-    let path_scheme = if ctor_scheme.ty.is_fn() {
-        let fn_ret = tcx.no_late_bound_regions(&ctor_scheme.ty.fn_ret()).unwrap();
-        ty::TypeScheme {
-            ty: fn_ret.unwrap(),
-            generics: ctor_scheme.generics,
-        }
-    } else {
-        ctor_scheme
-    };
-    self.instantiate_path(segments, path_scheme, &ctor_predicates,
-                          opt_ty, def, pat.span, pat.id);
-
-    let report_bad_struct_kind = |is_warning| {
-        bad_struct_kind_err(tcx.sess, pat, path, is_warning);
-        if is_warning { return; }
-        self.write_error(pat.id);
-        if let Some(subpats) = subpats {
-            for pat in subpats {
-                self.check_pat(&pat, tcx.types.err);
+        let real_path_ty = self.node_ty(pat.id);
+        let (kind_name, variant, expected_substs) = match real_path_ty.sty {
+            ty::TyEnum(enum_def, expected_substs) => {
+                let variant = enum_def.variant_of_def(def);
+                ("variant", variant, expected_substs)
             }
-        }
-    };
-
-    // If we didn't have a fully resolved path to start with, we had an
-    // associated const, and we should quit now, since the rest of this
-    // function uses checks specific to structs and enums.
-    if path_res.depth != 0 {
-        if is_tuple_struct_pat {
-            report_bad_struct_kind(false);
-        } else {
-            let pat_ty = self.node_ty(pat.id);
-            self.demand_suptype(pat.span, expected, pat_ty);
-        }
-        return;
-    }
-
-    let pat_ty = self.node_ty(pat.id);
-    self.demand_eqtype(pat.span, expected, pat_ty);
-
-    let real_path_ty = self.node_ty(pat.id);
-    let (kind_name, variant, expected_substs) = match real_path_ty.sty {
-        ty::TyEnum(enum_def, expected_substs) => {
-            let variant = enum_def.variant_of_def(def);
-            ("variant", variant, expected_substs)
-        }
-        ty::TyStruct(struct_def, expected_substs) => {
-            let variant = struct_def.struct_variant();
-            ("struct", variant, expected_substs)
-        }
-        _ => {
-            report_bad_struct_kind(false);
-            return;
-        }
-    };
-
-    match (is_tuple_struct_pat, variant.kind()) {
-        (true, ty::VariantKind::Unit) => {
-            // Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
-            // is allowed for backward compatibility.
-            report_bad_struct_kind(true);
-        }
-        (_, ty::VariantKind::Struct) => {
-            report_bad_struct_kind(false);
-            return
-        }
-        _ => {}
-    }
-
-    if let Some(subpats) = subpats {
-        if subpats.len() == variant.fields.len() {
-            for (subpat, field) in subpats.iter().zip(&variant.fields) {
-                let field_ty = self.field_ty(subpat.span, field, expected_substs);
-                self.check_pat(&subpat, field_ty);
+            ty::TyStruct(struct_def, expected_substs) => {
+                let variant = struct_def.struct_variant();
+                ("struct", variant, expected_substs)
             }
-        } else if variant.fields.is_empty() {
-            span_err!(tcx.sess, pat.span, E0024,
-                      "this pattern has {} field{}, but the corresponding {} has no fields",
-                      subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name);
-
-            for pat in subpats {
-                self.check_pat(&pat, tcx.types.err);
-            }
-        } else {
-            span_err!(tcx.sess, pat.span, E0023,
-                      "this pattern has {} field{}, but the corresponding {} has {} field{}",
-                      subpats.len(), if subpats.len() == 1 {""} else {"s"},
-                      kind_name,
-                      variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"});
-
-            for pat in subpats {
-                self.check_pat(&pat, tcx.types.err);
-            }
-        }
-    }
-}
-
-/// `path` is the AST path item naming the type of this struct.
-/// `fields` is the field patterns of the struct pattern.
-/// `struct_fields` describes the type of each field of the struct.
-/// `struct_id` is the ID of the struct.
-/// `etc` is true if the pattern said '...' and false otherwise.
-pub fn check_struct_pat_fields(&self,
-                               span: Span,
-                               fields: &'gcx [Spanned<hir::FieldPat>],
-                               variant: ty::VariantDef<'tcx>,
-                               substs: &Substs<'tcx>,
-                               etc: bool) {
-    let tcx = self.tcx;
-
-    // Index the struct fields' types.
-    let field_map = variant.fields
-        .iter()
-        .map(|field| (field.name, field))
-        .collect::<FnvHashMap<_, _>>();
-
-    // Keep track of which fields have already appeared in the pattern.
-    let mut used_fields = FnvHashMap();
-
-    // Typecheck each field.
-    for &Spanned { node: ref field, span } in fields {
-        let field_ty = match used_fields.entry(field.name) {
-            Occupied(occupied) => {
-                let mut err = struct_span_err!(tcx.sess, span, E0025,
-                                               "field `{}` bound multiple times in the pattern",
-                                               field.name);
-                span_note!(&mut err, *occupied.get(),
-                           "field `{}` previously bound here",
-                           field.name);
-                err.emit();
-                tcx.types.err
-            }
-            Vacant(vacant) => {
-                vacant.insert(span);
-                field_map.get(&field.name)
-                    .map(|f| self.field_ty(span, f, substs))
-                    .unwrap_or_else(|| {
-                        span_err!(tcx.sess, span, E0026,
-                            "struct `{}` does not have a field named `{}`",
-                            tcx.item_path_str(variant.did),
-                            field.name);
-                        tcx.types.err
-                    })
+            _ => {
+                report_bad_struct_kind(false);
+                return;
             }
         };
 
-        self.check_pat(&field.pat, field_ty);
+        match (is_tuple_struct_pat, variant.kind()) {
+            (true, ty::VariantKind::Unit) => {
+                // Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
+                // is allowed for backward compatibility.
+                report_bad_struct_kind(true);
+            }
+            (_, ty::VariantKind::Struct) => {
+                report_bad_struct_kind(false);
+                return
+            }
+            _ => {}
+        }
+
+        if let Some(subpats) = subpats {
+            if subpats.len() == variant.fields.len() {
+                for (subpat, field) in subpats.iter().zip(&variant.fields) {
+                    let field_ty = self.field_ty(subpat.span, field, expected_substs);
+                    self.check_pat(&subpat, field_ty);
+                }
+            } else if variant.fields.is_empty() {
+                span_err!(tcx.sess, pat.span, E0024,
+                          "this pattern has {} field{}, but the corresponding {} has no fields",
+                          subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name);
+
+                for pat in subpats {
+                    self.check_pat(&pat, tcx.types.err);
+                }
+            } else {
+                span_err!(tcx.sess, pat.span, E0023,
+                          "this pattern has {} field{}, but the corresponding {} has {} field{}",
+                          subpats.len(), if subpats.len() == 1 {""} else {"s"},
+                          kind_name,
+                          variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"});
+
+                for pat in subpats {
+                    self.check_pat(&pat, tcx.types.err);
+                }
+            }
+        }
     }
 
-    // Report an error if not all the fields were specified.
-    if !etc {
-        for field in variant.fields
+    /// `path` is the AST path item naming the type of this struct.
+    /// `fields` is the field patterns of the struct pattern.
+    /// `struct_fields` describes the type of each field of the struct.
+    /// `struct_id` is the ID of the struct.
+    /// `etc` is true if the pattern said '...' and false otherwise.
+    pub fn check_struct_pat_fields(&self,
+                                   span: Span,
+                                   fields: &'gcx [Spanned<hir::FieldPat>],
+                                   variant: ty::VariantDef<'tcx>,
+                                   substs: &Substs<'tcx>,
+                                   etc: bool) {
+        let tcx = self.tcx;
+
+        // Index the struct fields' types.
+        let field_map = variant.fields
             .iter()
-            .filter(|field| !used_fields.contains_key(&field.name)) {
-            span_err!(tcx.sess, span, E0027,
-                "pattern does not mention field `{}`",
-                field.name);
+            .map(|field| (field.name, field))
+            .collect::<FnvHashMap<_, _>>();
+
+        // Keep track of which fields have already appeared in the pattern.
+        let mut used_fields = FnvHashMap();
+
+        // Typecheck each field.
+        for &Spanned { node: ref field, span } in fields {
+            let field_ty = match used_fields.entry(field.name) {
+                Occupied(occupied) => {
+                    let mut err = struct_span_err!(tcx.sess, span, E0025,
+                                                   "field `{}` bound multiple times \
+                                                    in the pattern",
+                                                   field.name);
+                    span_note!(&mut err, *occupied.get(),
+                               "field `{}` previously bound here",
+                               field.name);
+                    err.emit();
+                    tcx.types.err
+                }
+                Vacant(vacant) => {
+                    vacant.insert(span);
+                    field_map.get(&field.name)
+                        .map(|f| self.field_ty(span, f, substs))
+                        .unwrap_or_else(|| {
+                            span_err!(tcx.sess, span, E0026,
+                                "struct `{}` does not have a field named `{}`",
+                                tcx.item_path_str(variant.did),
+                                field.name);
+                            tcx.types.err
+                        })
+                }
+            };
+
+            self.check_pat(&field.pat, field_ty);
+        }
+
+        // Report an error if not all the fields were specified.
+        if !etc {
+            for field in variant.fields
+                .iter()
+                .filter(|field| !used_fields.contains_key(&field.name)) {
+                span_err!(tcx.sess, span, E0027,
+                    "pattern does not mention field `{}`",
+                    field.name);
+            }
         }
     }
 }
-}
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 9de78168fe7..7493ca70f55 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -64,267 +64,267 @@ enum CallStep<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-pub fn check_call(&self,
-                  call_expr: &'gcx hir::Expr,
-                  callee_expr: &'gcx hir::Expr,
-                  arg_exprs: &'gcx [P<hir::Expr>],
-                  expected: Expectation<'tcx>)
-{
-    self.check_expr(callee_expr);
-    let original_callee_ty = self.expr_ty(callee_expr);
-    let (callee_ty, _, result) =
-        self.autoderef(callee_expr.span,
-                       original_callee_ty,
-                       || Some(callee_expr),
-                       UnresolvedTypeAction::Error,
-                       LvaluePreference::NoPreference,
-                       |adj_ty, idx| {
-            self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
-    });
+    pub fn check_call(&self,
+                      call_expr: &'gcx hir::Expr,
+                      callee_expr: &'gcx hir::Expr,
+                      arg_exprs: &'gcx [P<hir::Expr>],
+                      expected: Expectation<'tcx>)
+    {
+        self.check_expr(callee_expr);
+        let original_callee_ty = self.expr_ty(callee_expr);
+        let (callee_ty, _, result) =
+            self.autoderef(callee_expr.span,
+                           original_callee_ty,
+                           || Some(callee_expr),
+                           UnresolvedTypeAction::Error,
+                           LvaluePreference::NoPreference,
+                           |adj_ty, idx| {
+                self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
+        });
 
-    match result {
-        None => {
-            // this will report an error since original_callee_ty is not a fn
-            self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected);
-        }
-
-        Some(CallStep::Builtin) => {
-            self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected);
-        }
-
-        Some(CallStep::DeferredClosure(fn_sig)) => {
-            self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig);
-        }
-
-        Some(CallStep::Overloaded(method_callee)) => {
-            self.confirm_overloaded_call(call_expr, callee_expr,
-                                         arg_exprs, expected, method_callee);
-        }
-    }
-}
-
-fn try_overloaded_call_step(&self,
-                            call_expr: &'gcx hir::Expr,
-                            callee_expr: &'gcx hir::Expr,
-                            adjusted_ty: Ty<'tcx>,
-                            autoderefs: usize)
-                            -> Option<CallStep<'tcx>>
-{
-    debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
-           call_expr,
-           adjusted_ty,
-           autoderefs);
-
-    // If the callee is a bare function or a closure, then we're all set.
-    match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty {
-        ty::TyFnDef(..) | ty::TyFnPtr(_) => {
-            self.write_autoderef_adjustment(callee_expr.id, autoderefs);
-            return Some(CallStep::Builtin);
-        }
-
-        ty::TyClosure(def_id, substs) => {
-            assert_eq!(def_id.krate, LOCAL_CRATE);
-
-            // Check whether this is a call to a closure where we
-            // haven't yet decided on whether the closure is fn vs
-            // fnmut vs fnonce. If so, we have to defer further processing.
-            if self.closure_kind(def_id).is_none() {
-                let closure_ty =
-                    self.closure_type(def_id, substs);
-                let fn_sig =
-                    self.replace_late_bound_regions_with_fresh_var(call_expr.span,
-                                                                   infer::FnCall,
-                                                                   &closure_ty.sig).0;
-                self.record_deferred_call_resolution(def_id, Box::new(CallResolution {
-                    call_expr: call_expr,
-                    callee_expr: callee_expr,
-                    adjusted_ty: adjusted_ty,
-                    autoderefs: autoderefs,
-                    fn_sig: fn_sig.clone(),
-                    closure_def_id: def_id
-                }));
-                return Some(CallStep::DeferredClosure(fn_sig));
+        match result {
+            None => {
+                // this will report an error since original_callee_ty is not a fn
+                self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected);
             }
-        }
 
-        // Hack: we know that there are traits implementing Fn for &F
-        // where F:Fn and so forth. In the particular case of types
-        // like `x: &mut FnMut()`, if there is a call `x()`, we would
-        // normally translate to `FnMut::call_mut(&mut x, ())`, but
-        // that winds up requiring `mut x: &mut FnMut()`. A little
-        // over the top. The simplest fix by far is to just ignore
-        // this case and deref again, so we wind up with
-        // `FnMut::call_mut(&mut *x, ())`.
-        ty::TyRef(..) if autoderefs == 0 => {
-            return None;
-        }
+            Some(CallStep::Builtin) => {
+                self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected);
+            }
 
-        _ => {}
-    }
+            Some(CallStep::DeferredClosure(fn_sig)) => {
+                self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig);
+            }
 
-    self.try_overloaded_call_traits(call_expr, callee_expr, adjusted_ty, autoderefs)
-        .map(|method_callee| CallStep::Overloaded(method_callee))
-}
-
-fn try_overloaded_call_traits(&self,
-                              call_expr: &hir::Expr,
-                              callee_expr: &hir::Expr,
-                              adjusted_ty: Ty<'tcx>,
-                              autoderefs: usize)
-                              -> Option<ty::MethodCallee<'tcx>>
-{
-    // Try the options that are least restrictive on the caller first.
-    for &(opt_trait_def_id, method_name) in &[
-        (self.tcx.lang_items.fn_trait(), token::intern("call")),
-        (self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")),
-        (self.tcx.lang_items.fn_once_trait(), token::intern("call_once")),
-    ] {
-        let trait_def_id = match opt_trait_def_id {
-            Some(def_id) => def_id,
-            None => continue,
-        };
-
-        match self.lookup_method_in_trait_adjusted(call_expr.span,
-                                                   Some(&callee_expr),
-                                                   method_name,
-                                                   trait_def_id,
-                                                   autoderefs,
-                                                   false,
-                                                   adjusted_ty,
-                                                   None) {
-            None => continue,
-            Some(method_callee) => {
-                return Some(method_callee);
+            Some(CallStep::Overloaded(method_callee)) => {
+                self.confirm_overloaded_call(call_expr, callee_expr,
+                                             arg_exprs, expected, method_callee);
             }
         }
     }
 
-    None
-}
+    fn try_overloaded_call_step(&self,
+                                call_expr: &'gcx hir::Expr,
+                                callee_expr: &'gcx hir::Expr,
+                                adjusted_ty: Ty<'tcx>,
+                                autoderefs: usize)
+                                -> Option<CallStep<'tcx>>
+    {
+        debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
+               call_expr,
+               adjusted_ty,
+               autoderefs);
 
-fn confirm_builtin_call(&self,
-                        call_expr: &hir::Expr,
-                        callee_ty: Ty<'tcx>,
-                        arg_exprs: &'gcx [P<hir::Expr>],
-                        expected: Expectation<'tcx>)
-{
-    let error_fn_sig;
+        // If the callee is a bare function or a closure, then we're all set.
+        match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty {
+            ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+                self.write_autoderef_adjustment(callee_expr.id, autoderefs);
+                return Some(CallStep::Builtin);
+            }
 
-    let fn_sig = match callee_ty.sty {
-        ty::TyFnDef(_, _, &ty::BareFnTy {ref sig, ..}) |
-        ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => {
-            sig
-        }
-        _ => {
-            let mut err = self.type_error_struct(call_expr.span, |actual| {
-                format!("expected function, found `{}`", actual)
-            }, callee_ty, None);
+            ty::TyClosure(def_id, substs) => {
+                assert_eq!(def_id.krate, LOCAL_CRATE);
 
-            if let hir::ExprCall(ref expr, _) = call_expr.node {
-                let tcx = self.tcx;
-                if let Some(pr) = tcx.def_map.borrow().get(&expr.id) {
-                    if pr.depth == 0 && pr.base_def != Def::Err {
-                        if let Some(span) = tcx.map.span_if_local(pr.def_id()) {
-                            err.span_note(span, "defined here");
-                        }
-                    }
+                // Check whether this is a call to a closure where we
+                // haven't yet decided on whether the closure is fn vs
+                // fnmut vs fnonce. If so, we have to defer further processing.
+                if self.closure_kind(def_id).is_none() {
+                    let closure_ty =
+                        self.closure_type(def_id, substs);
+                    let fn_sig =
+                        self.replace_late_bound_regions_with_fresh_var(call_expr.span,
+                                                                       infer::FnCall,
+                                                                       &closure_ty.sig).0;
+                    self.record_deferred_call_resolution(def_id, Box::new(CallResolution {
+                        call_expr: call_expr,
+                        callee_expr: callee_expr,
+                        adjusted_ty: adjusted_ty,
+                        autoderefs: autoderefs,
+                        fn_sig: fn_sig.clone(),
+                        closure_def_id: def_id
+                    }));
+                    return Some(CallStep::DeferredClosure(fn_sig));
                 }
             }
 
-            err.emit();
+            // Hack: we know that there are traits implementing Fn for &F
+            // where F:Fn and so forth. In the particular case of types
+            // like `x: &mut FnMut()`, if there is a call `x()`, we would
+            // normally translate to `FnMut::call_mut(&mut x, ())`, but
+            // that winds up requiring `mut x: &mut FnMut()`. A little
+            // over the top. The simplest fix by far is to just ignore
+            // this case and deref again, so we wind up with
+            // `FnMut::call_mut(&mut *x, ())`.
+            ty::TyRef(..) if autoderefs == 0 => {
+                return None;
+            }
 
-            // This is the "default" function signature, used in case of error.
-            // In that case, we check each argument against "error" in order to
-            // set up all the node type bindings.
-            error_fn_sig = ty::Binder(ty::FnSig {
-                inputs: self.err_args(arg_exprs.len()),
-                output: ty::FnConverging(self.tcx.types.err),
-                variadic: false
-            });
-
-            &error_fn_sig
+            _ => {}
         }
-    };
 
-    // Replace any late-bound regions that appear in the function
-    // signature with region variables. We also have to
-    // renormalize the associated types at this point, since they
-    // previously appeared within a `Binder<>` and hence would not
-    // have been normalized before.
-    let fn_sig =
-        self.replace_late_bound_regions_with_fresh_var(call_expr.span,
-                                                       infer::FnCall,
-                                                       fn_sig).0;
-    let fn_sig =
-        self.normalize_associated_types_in(call_expr.span, &fn_sig);
+        self.try_overloaded_call_traits(call_expr, callee_expr, adjusted_ty, autoderefs)
+            .map(|method_callee| CallStep::Overloaded(method_callee))
+    }
 
-    // Call the generic checker.
-    let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span,
-                                                           expected,
-                                                           fn_sig.output,
-                                                           &fn_sig.inputs);
-    self.check_argument_types(call_expr.span,
-                              &fn_sig.inputs,
-                              &expected_arg_tys[..],
-                              arg_exprs,
-                              fn_sig.variadic,
-                              TupleArgumentsFlag::DontTupleArguments);
+    fn try_overloaded_call_traits(&self,
+                                  call_expr: &hir::Expr,
+                                  callee_expr: &hir::Expr,
+                                  adjusted_ty: Ty<'tcx>,
+                                  autoderefs: usize)
+                                  -> Option<ty::MethodCallee<'tcx>>
+    {
+        // Try the options that are least restrictive on the caller first.
+        for &(opt_trait_def_id, method_name) in &[
+            (self.tcx.lang_items.fn_trait(), token::intern("call")),
+            (self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")),
+            (self.tcx.lang_items.fn_once_trait(), token::intern("call_once")),
+        ] {
+            let trait_def_id = match opt_trait_def_id {
+                Some(def_id) => def_id,
+                None => continue,
+            };
 
-    self.write_call(call_expr, fn_sig.output);
-}
+            match self.lookup_method_in_trait_adjusted(call_expr.span,
+                                                       Some(&callee_expr),
+                                                       method_name,
+                                                       trait_def_id,
+                                                       autoderefs,
+                                                       false,
+                                                       adjusted_ty,
+                                                       None) {
+                None => continue,
+                Some(method_callee) => {
+                    return Some(method_callee);
+                }
+            }
+        }
 
-fn confirm_deferred_closure_call(&self,
-                                 call_expr: &hir::Expr,
-                                 arg_exprs: &'gcx [P<hir::Expr>],
-                                 expected: Expectation<'tcx>,
-                                 fn_sig: ty::FnSig<'tcx>)
-{
-    // `fn_sig` is the *signature* of the cosure being called. We
-    // don't know the full details yet (`Fn` vs `FnMut` etc), but we
-    // do know the types expected for each argument and the return
-    // type.
+        None
+    }
 
-    let expected_arg_tys =
-        self.expected_types_for_fn_args(call_expr.span,
-                                        expected,
-                                        fn_sig.output.clone(),
-                                        &fn_sig.inputs);
+    fn confirm_builtin_call(&self,
+                            call_expr: &hir::Expr,
+                            callee_ty: Ty<'tcx>,
+                            arg_exprs: &'gcx [P<hir::Expr>],
+                            expected: Expectation<'tcx>)
+    {
+        let error_fn_sig;
 
-    self.check_argument_types(call_expr.span,
-                              &fn_sig.inputs,
-                              &expected_arg_tys,
-                              arg_exprs,
-                              fn_sig.variadic,
-                              TupleArgumentsFlag::TupleArguments);
+        let fn_sig = match callee_ty.sty {
+            ty::TyFnDef(_, _, &ty::BareFnTy {ref sig, ..}) |
+            ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => {
+                sig
+            }
+            _ => {
+                let mut err = self.type_error_struct(call_expr.span, |actual| {
+                    format!("expected function, found `{}`", actual)
+                }, callee_ty, None);
 
-    self.write_call(call_expr, fn_sig.output);
-}
+                if let hir::ExprCall(ref expr, _) = call_expr.node {
+                    let tcx = self.tcx;
+                    if let Some(pr) = tcx.def_map.borrow().get(&expr.id) {
+                        if pr.depth == 0 && pr.base_def != Def::Err {
+                            if let Some(span) = tcx.map.span_if_local(pr.def_id()) {
+                                err.span_note(span, "defined here");
+                            }
+                        }
+                    }
+                }
 
-fn confirm_overloaded_call(&self,
-                           call_expr: &hir::Expr,
-                           callee_expr: &'gcx hir::Expr,
-                           arg_exprs: &'gcx [P<hir::Expr>],
-                           expected: Expectation<'tcx>,
-                           method_callee: ty::MethodCallee<'tcx>)
-{
-    let output_type =
-        self.check_method_argument_types(call_expr.span,
-                                         method_callee.ty,
-                                         callee_expr,
-                                         arg_exprs,
-                                         TupleArgumentsFlag::TupleArguments,
-                                         expected);
-    self.write_call(call_expr, output_type);
+                err.emit();
 
-    self.write_overloaded_call_method_map(call_expr, method_callee);
-}
+                // This is the "default" function signature, used in case of error.
+                // In that case, we check each argument against "error" in order to
+                // set up all the node type bindings.
+                error_fn_sig = ty::Binder(ty::FnSig {
+                    inputs: self.err_args(arg_exprs.len()),
+                    output: ty::FnConverging(self.tcx.types.err),
+                    variadic: false
+                });
 
-fn write_overloaded_call_method_map(&self,
-                                    call_expr: &hir::Expr,
-                                    method_callee: ty::MethodCallee<'tcx>) {
-    let method_call = ty::MethodCall::expr(call_expr.id);
-    self.tables.borrow_mut().method_map.insert(method_call, method_callee);
-}
+                &error_fn_sig
+            }
+        };
+
+        // Replace any late-bound regions that appear in the function
+        // signature with region variables. We also have to
+        // renormalize the associated types at this point, since they
+        // previously appeared within a `Binder<>` and hence would not
+        // have been normalized before.
+        let fn_sig =
+            self.replace_late_bound_regions_with_fresh_var(call_expr.span,
+                                                           infer::FnCall,
+                                                           fn_sig).0;
+        let fn_sig =
+            self.normalize_associated_types_in(call_expr.span, &fn_sig);
+
+        // Call the generic checker.
+        let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span,
+                                                               expected,
+                                                               fn_sig.output,
+                                                               &fn_sig.inputs);
+        self.check_argument_types(call_expr.span,
+                                  &fn_sig.inputs,
+                                  &expected_arg_tys[..],
+                                  arg_exprs,
+                                  fn_sig.variadic,
+                                  TupleArgumentsFlag::DontTupleArguments);
+
+        self.write_call(call_expr, fn_sig.output);
+    }
+
+    fn confirm_deferred_closure_call(&self,
+                                     call_expr: &hir::Expr,
+                                     arg_exprs: &'gcx [P<hir::Expr>],
+                                     expected: Expectation<'tcx>,
+                                     fn_sig: ty::FnSig<'tcx>)
+    {
+        // `fn_sig` is the *signature* of the cosure being called. We
+        // don't know the full details yet (`Fn` vs `FnMut` etc), but we
+        // do know the types expected for each argument and the return
+        // type.
+
+        let expected_arg_tys =
+            self.expected_types_for_fn_args(call_expr.span,
+                                            expected,
+                                            fn_sig.output.clone(),
+                                            &fn_sig.inputs);
+
+        self.check_argument_types(call_expr.span,
+                                  &fn_sig.inputs,
+                                  &expected_arg_tys,
+                                  arg_exprs,
+                                  fn_sig.variadic,
+                                  TupleArgumentsFlag::TupleArguments);
+
+        self.write_call(call_expr, fn_sig.output);
+    }
+
+    fn confirm_overloaded_call(&self,
+                               call_expr: &hir::Expr,
+                               callee_expr: &'gcx hir::Expr,
+                               arg_exprs: &'gcx [P<hir::Expr>],
+                               expected: Expectation<'tcx>,
+                               method_callee: ty::MethodCallee<'tcx>)
+    {
+        let output_type =
+            self.check_method_argument_types(call_expr.span,
+                                             method_callee.ty,
+                                             callee_expr,
+                                             arg_exprs,
+                                             TupleArgumentsFlag::TupleArguments,
+                                             expected);
+        self.write_call(call_expr, output_type);
+
+        self.write_overloaded_call_method_map(call_expr, method_callee);
+    }
+
+    fn write_overloaded_call_method_map(&self,
+                                        call_expr: &hir::Expr,
+                                        method_callee: ty::MethodCallee<'tcx>) {
+        let method_call = ty::MethodCall::expr(call_expr.id);
+        self.tables.borrow_mut().method_map.insert(method_call, method_callee);
+    }
 }
 
 #[derive(Debug)]
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index bdf26eab20f..690250edb8c 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -73,26 +73,26 @@ enum UnsizeKind<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-/// Returns the kind of unsize information of t, or None
-/// if t is sized or it is unknown.
-fn unsize_kind(&self, t: Ty<'tcx>) -> Option<UnsizeKind<'tcx>> {
-    match t.sty {
-        ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length),
-        ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())),
-        ty::TyStruct(def, substs) => {
-            // FIXME(arielb1): do some kind of normalization
-            match def.struct_variant().fields.last() {
-                None => None,
-                Some(f) => self.unsize_kind(f.ty(self.tcx, substs))
+    /// Returns the kind of unsize information of t, or None
+    /// if t is sized or it is unknown.
+    fn unsize_kind(&self, t: Ty<'tcx>) -> Option<UnsizeKind<'tcx>> {
+        match t.sty {
+            ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length),
+            ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())),
+            ty::TyStruct(def, substs) => {
+                // FIXME(arielb1): do some kind of normalization
+                match def.struct_variant().fields.last() {
+                    None => None,
+                    Some(f) => self.unsize_kind(f.ty(self.tcx, substs))
+                }
             }
+            // We should really try to normalize here.
+            ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
+            ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)),
+            _ => None
         }
-        // We should really try to normalize here.
-        ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
-        ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)),
-        _ => None
     }
 }
-}
 
 #[derive(Copy, Clone)]
 enum CastError {
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 43c1f9d367e..d3396eb4c1b 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -20,227 +20,227 @@ use syntax::abi::Abi;
 use rustc::hir;
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-pub fn check_expr_closure(&self,
-                          expr: &hir::Expr,
-                          _capture: hir::CaptureClause,
-                          decl: &'gcx hir::FnDecl,
-                          body: &'gcx hir::Block,
-                          expected: Expectation<'tcx>) {
-    debug!("check_expr_closure(expr={:?},expected={:?})",
-           expr,
-           expected);
+    pub fn check_expr_closure(&self,
+                              expr: &hir::Expr,
+                              _capture: hir::CaptureClause,
+                              decl: &'gcx hir::FnDecl,
+                              body: &'gcx hir::Block,
+                              expected: Expectation<'tcx>) {
+        debug!("check_expr_closure(expr={:?},expected={:?})",
+               expr,
+               expected);
 
-    // It's always helpful for inference if we know the kind of
-    // closure sooner rather than later, so first examine the expected
-    // type, and see if can glean a closure kind from there.
-    let (expected_sig,expected_kind) = match expected.to_option(self) {
-        Some(ty) => self.deduce_expectations_from_expected_type(ty),
-        None => (None, None)
-    };
-    self.check_closure(expr, expected_kind, decl, body, expected_sig)
-}
-
-fn check_closure(&self,
-                 expr: &hir::Expr,
-                 opt_kind: Option<ty::ClosureKind>,
-                 decl: &'gcx hir::FnDecl,
-                 body: &'gcx hir::Block,
-                 expected_sig: Option<ty::FnSig<'tcx>>) {
-    let expr_def_id = self.tcx.map.local_def_id(expr.id);
-
-    debug!("check_closure opt_kind={:?} expected_sig={:?}",
-           opt_kind,
-           expected_sig);
-
-    let mut fn_ty = AstConv::ty_of_closure(self,
-                                           hir::Unsafety::Normal,
-                                           decl,
-                                           Abi::RustCall,
-                                           expected_sig);
-
-    // Create type variables (for now) to represent the transformed
-    // types of upvars. These will be unified during the upvar
-    // inference phase (`upvar.rs`).
-    let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len());
-    let upvar_tys = self.next_ty_vars(num_upvars);
-
-    debug!("check_closure: expr.id={:?} upvar_tys={:?}",
-           expr.id, upvar_tys);
-
-    let closure_type = self.tcx.mk_closure(expr_def_id,
-        self.parameter_environment.free_substs,
-        upvar_tys);
-
-    self.write_ty(expr.id, closure_type);
-
-    let fn_sig = self.tcx.liberate_late_bound_regions(
-        self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
-
-    check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body);
-
-    // Tuple up the arguments and insert the resulting function type into
-    // the `closures` table.
-    fn_ty.sig.0.inputs = vec![self.tcx.mk_tup(fn_ty.sig.0.inputs)];
-
-    debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
-           expr_def_id,
-           fn_ty.sig,
-           opt_kind);
-
-    self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
-    match opt_kind {
-        Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
-        None => { }
+        // It's always helpful for inference if we know the kind of
+        // closure sooner rather than later, so first examine the expected
+        // type, and see if can glean a closure kind from there.
+        let (expected_sig,expected_kind) = match expected.to_option(self) {
+            Some(ty) => self.deduce_expectations_from_expected_type(ty),
+            None => (None, None)
+        };
+        self.check_closure(expr, expected_kind, decl, body, expected_sig)
     }
-}
 
-fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
-    -> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
-{
-    debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
-           expected_ty);
+    fn check_closure(&self,
+                     expr: &hir::Expr,
+                     opt_kind: Option<ty::ClosureKind>,
+                     decl: &'gcx hir::FnDecl,
+                     body: &'gcx hir::Block,
+                     expected_sig: Option<ty::FnSig<'tcx>>) {
+        let expr_def_id = self.tcx.map.local_def_id(expr.id);
 
-    match expected_ty.sty {
-        ty::TyTrait(ref object_type) => {
-            let proj_bounds = object_type.projection_bounds_with_self_ty(self.tcx,
-                                                                         self.tcx.types.err);
-            let sig = proj_bounds.iter()
-                                 .filter_map(|pb| self.deduce_sig_from_projection(pb))
-                                 .next();
-            let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal_def_id());
-            (sig, kind)
-        }
-        ty::TyInfer(ty::TyVar(vid)) => {
-            self.deduce_expectations_from_obligations(vid)
-        }
-        _ => {
-            (None, None)
+        debug!("check_closure opt_kind={:?} expected_sig={:?}",
+               opt_kind,
+               expected_sig);
+
+        let mut fn_ty = AstConv::ty_of_closure(self,
+                                               hir::Unsafety::Normal,
+                                               decl,
+                                               Abi::RustCall,
+                                               expected_sig);
+
+        // Create type variables (for now) to represent the transformed
+        // types of upvars. These will be unified during the upvar
+        // inference phase (`upvar.rs`).
+        let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len());
+        let upvar_tys = self.next_ty_vars(num_upvars);
+
+        debug!("check_closure: expr.id={:?} upvar_tys={:?}",
+               expr.id, upvar_tys);
+
+        let closure_type = self.tcx.mk_closure(expr_def_id,
+            self.parameter_environment.free_substs,
+            upvar_tys);
+
+        self.write_ty(expr.id, closure_type);
+
+        let fn_sig = self.tcx.liberate_late_bound_regions(
+            self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
+
+        check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body);
+
+        // Tuple up the arguments and insert the resulting function type into
+        // the `closures` table.
+        fn_ty.sig.0.inputs = vec![self.tcx.mk_tup(fn_ty.sig.0.inputs)];
+
+        debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
+               expr_def_id,
+               fn_ty.sig,
+               opt_kind);
+
+        self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
+        match opt_kind {
+            Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
+            None => { }
         }
     }
-}
 
-fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid)
-    -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
-{
-    let fulfillment_cx = self.fulfillment_cx.borrow();
-    // Here `expected_ty` is known to be a type inference variable.
+    fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
+        -> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
+    {
+        debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
+               expected_ty);
 
-    let expected_sig =
-        fulfillment_cx
-        .pending_obligations()
-        .iter()
-        .map(|obligation| &obligation.obligation)
-        .filter_map(|obligation| {
-            debug!("deduce_expectations_from_obligations: obligation.predicate={:?}",
-                   obligation.predicate);
-
-            match obligation.predicate {
-                // Given a Projection predicate, we can potentially infer
-                // the complete signature.
-                ty::Predicate::Projection(ref proj_predicate) => {
-                    let trait_ref = proj_predicate.to_poly_trait_ref();
-                    self.self_type_matches_expected_vid(trait_ref, expected_vid)
-                        .and_then(|_| self.deduce_sig_from_projection(proj_predicate))
-                }
-                _ => {
-                    None
-                }
+        match expected_ty.sty {
+            ty::TyTrait(ref object_type) => {
+                let proj_bounds = object_type.projection_bounds_with_self_ty(self.tcx,
+                                                                             self.tcx.types.err);
+                let sig = proj_bounds.iter()
+                                     .filter_map(|pb| self.deduce_sig_from_projection(pb))
+                                     .next();
+                let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal_def_id());
+                (sig, kind)
             }
-        })
-        .next();
-
-    // Even if we can't infer the full signature, we may be able to
-    // infer the kind. This can occur if there is a trait-reference
-    // like `F : Fn<A>`. Note that due to subtyping we could encounter
-    // many viable options, so pick the most restrictive.
-    let expected_kind =
-        fulfillment_cx
-        .pending_obligations()
-        .iter()
-        .map(|obligation| &obligation.obligation)
-        .filter_map(|obligation| {
-            let opt_trait_ref = match obligation.predicate {
-                ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
-                ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
-                ty::Predicate::Equate(..) => None,
-                ty::Predicate::RegionOutlives(..) => None,
-                ty::Predicate::TypeOutlives(..) => None,
-                ty::Predicate::WellFormed(..) => None,
-                ty::Predicate::ObjectSafe(..) => None,
-                ty::Predicate::Rfc1592(..) => None,
-
-                // NB: This predicate is created by breaking down a
-                // `ClosureType: FnFoo()` predicate, where
-                // `ClosureType` represents some `TyClosure`. It can't
-                // possibly be referring to the current closure,
-                // because we haven't produced the `TyClosure` for
-                // this closure yet; this is exactly why the other
-                // code is looking for a self type of a unresolved
-                // inference variable.
-                ty::Predicate::ClosureKind(..) => None,
-            };
-            opt_trait_ref
-                .and_then(|trait_ref| self.self_type_matches_expected_vid(trait_ref, expected_vid))
-                .and_then(|trait_ref| self.tcx.lang_items.fn_trait_kind(trait_ref.def_id()))
-        })
-        .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
-
-    (expected_sig, expected_kind)
-}
-
-/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
-/// everything we need to know about a closure.
-fn deduce_sig_from_projection(&self,
-    projection: &ty::PolyProjectionPredicate<'tcx>)
-    -> Option<ty::FnSig<'tcx>>
-{
-    let tcx = self.tcx;
-
-    debug!("deduce_sig_from_projection({:?})",
-           projection);
-
-    let trait_ref = projection.to_poly_trait_ref();
-
-    if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
-        return None;
+            ty::TyInfer(ty::TyVar(vid)) => {
+                self.deduce_expectations_from_obligations(vid)
+            }
+            _ => {
+                (None, None)
+            }
+        }
     }
 
-    let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
-    let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
-    debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
+    fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid)
+        -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
+    {
+        let fulfillment_cx = self.fulfillment_cx.borrow();
+        // Here `expected_ty` is known to be a type inference variable.
 
-    let input_tys = match arg_param_ty.sty {
-        ty::TyTuple(tys) => tys.to_vec(),
-        _ => { return None; }
-    };
-    debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
+        let expected_sig =
+            fulfillment_cx
+            .pending_obligations()
+            .iter()
+            .map(|obligation| &obligation.obligation)
+            .filter_map(|obligation| {
+                debug!("deduce_expectations_from_obligations: obligation.predicate={:?}",
+                       obligation.predicate);
 
-    let ret_param_ty = projection.0.ty;
-    let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
-    debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
+                match obligation.predicate {
+                    // Given a Projection predicate, we can potentially infer
+                    // the complete signature.
+                    ty::Predicate::Projection(ref proj_predicate) => {
+                        let trait_ref = proj_predicate.to_poly_trait_ref();
+                        self.self_type_matches_expected_vid(trait_ref, expected_vid)
+                            .and_then(|_| self.deduce_sig_from_projection(proj_predicate))
+                    }
+                    _ => {
+                        None
+                    }
+                }
+            })
+            .next();
 
-    let fn_sig = ty::FnSig {
-        inputs: input_tys,
-        output: ty::FnConverging(ret_param_ty),
-        variadic: false
-    };
-    debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
+        // Even if we can't infer the full signature, we may be able to
+        // infer the kind. This can occur if there is a trait-reference
+        // like `F : Fn<A>`. Note that due to subtyping we could encounter
+        // many viable options, so pick the most restrictive.
+        let expected_kind =
+            fulfillment_cx
+            .pending_obligations()
+            .iter()
+            .map(|obligation| &obligation.obligation)
+            .filter_map(|obligation| {
+                let opt_trait_ref = match obligation.predicate {
+                    ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
+                    ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
+                    ty::Predicate::Equate(..) => None,
+                    ty::Predicate::RegionOutlives(..) => None,
+                    ty::Predicate::TypeOutlives(..) => None,
+                    ty::Predicate::WellFormed(..) => None,
+                    ty::Predicate::ObjectSafe(..) => None,
+                    ty::Predicate::Rfc1592(..) => None,
 
-    Some(fn_sig)
-}
+                    // NB: This predicate is created by breaking down a
+                    // `ClosureType: FnFoo()` predicate, where
+                    // `ClosureType` represents some `TyClosure`. It can't
+                    // possibly be referring to the current closure,
+                    // because we haven't produced the `TyClosure` for
+                    // this closure yet; this is exactly why the other
+                    // code is looking for a self type of a unresolved
+                    // inference variable.
+                    ty::Predicate::ClosureKind(..) => None,
+                };
+                opt_trait_ref
+                    .and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
+                    .and_then(|tr| self.tcx.lang_items.fn_trait_kind(tr.def_id()))
+            })
+            .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
 
-fn self_type_matches_expected_vid(&self,
-    trait_ref: ty::PolyTraitRef<'tcx>,
-    expected_vid: ty::TyVid)
-    -> Option<ty::PolyTraitRef<'tcx>>
-{
-    let self_ty = self.shallow_resolve(trait_ref.self_ty());
-    debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
-           trait_ref,
-           self_ty);
-    match self_ty.sty {
-        ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
-        _ => None,
+        (expected_sig, expected_kind)
+    }
+
+    /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
+    /// everything we need to know about a closure.
+    fn deduce_sig_from_projection(&self,
+        projection: &ty::PolyProjectionPredicate<'tcx>)
+        -> Option<ty::FnSig<'tcx>>
+    {
+        let tcx = self.tcx;
+
+        debug!("deduce_sig_from_projection({:?})",
+               projection);
+
+        let trait_ref = projection.to_poly_trait_ref();
+
+        if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
+            return None;
+        }
+
+        let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
+        let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
+        debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
+
+        let input_tys = match arg_param_ty.sty {
+            ty::TyTuple(tys) => tys.to_vec(),
+            _ => { return None; }
+        };
+        debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
+
+        let ret_param_ty = projection.0.ty;
+        let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
+        debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
+
+        let fn_sig = ty::FnSig {
+            inputs: input_tys,
+            output: ty::FnConverging(ret_param_ty),
+            variadic: false
+        };
+        debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
+
+        Some(fn_sig)
+    }
+
+    fn self_type_matches_expected_vid(&self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        expected_vid: ty::TyVid)
+        -> Option<ty::PolyTraitRef<'tcx>>
+    {
+        let self_ty = self.shallow_resolve(trait_ref.self_ty());
+        debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
+               trait_ref,
+               self_ty);
+        match self_ty.sty {
+            ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
+            _ => None,
+        }
     }
 }
-}
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 55786a03eeb..4861ab15e2c 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -618,167 +618,167 @@ fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>,
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-/// Attempt to coerce an expression to a type, and return the
-/// adjusted type of the expression, if successful.
-/// Adjustments are only recorded if the coercion succeeded.
-/// The expressions *must not* have any pre-existing adjustments.
-pub fn try_coerce(&self,
-                  expr: &hir::Expr,
-                  target: Ty<'tcx>)
-                  -> RelateResult<'tcx, Ty<'tcx>> {
-    let source = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
-    debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
+    /// Attempt to coerce an expression to a type, and return the
+    /// adjusted type of the expression, if successful.
+    /// Adjustments are only recorded if the coercion succeeded.
+    /// The expressions *must not* have any pre-existing adjustments.
+    pub fn try_coerce(&self,
+                      expr: &hir::Expr,
+                      target: Ty<'tcx>)
+                      -> RelateResult<'tcx, Ty<'tcx>> {
+        let source = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
+        debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
-    let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
-    self.commit_if_ok(|_| {
-        let (ty, adjustment) =
-            apply(&mut coerce, &|| Some(expr), source, target)?;
-        if !adjustment.is_identity() {
-            debug!("Success, coerced with {:?}", adjustment);
-            assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
-            self.write_adjustment(expr.id, adjustment);
+        let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
+        self.commit_if_ok(|_| {
+            let (ty, adjustment) =
+                apply(&mut coerce, &|| Some(expr), source, target)?;
+            if !adjustment.is_identity() {
+                debug!("Success, coerced with {:?}", adjustment);
+                assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
+                self.write_adjustment(expr.id, adjustment);
+            }
+            Ok(ty)
+        })
+    }
+
+    /// Given some expressions, their known unified type and another expression,
+    /// tries to unify the types, potentially inserting coercions on any of the
+    /// provided expressions and returns their LUB (aka "common supertype").
+    pub fn try_find_coercion_lub<'b, E, I>(&self,
+                                           origin: TypeOrigin,
+                                           exprs: E,
+                                           prev_ty: Ty<'tcx>,
+                                           new: &'b hir::Expr)
+                                           -> RelateResult<'tcx, Ty<'tcx>>
+        // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
+        where E: Fn() -> I,
+              I: IntoIterator<Item=&'b hir::Expr> {
+
+        let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
+        let new_ty = self.resolve_type_vars_with_obligations(self.expr_ty(new));
+        debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
+
+        let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
+
+        // Special-case that coercion alone cannot handle:
+        // Two function item types of differing IDs or Substs.
+        match (&prev_ty.sty, &new_ty.sty) {
+            (&ty::TyFnDef(a_def_id, a_substs, a_fty),
+             &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
+                // The signature must always match.
+                let fty = self.lub(true, trace.clone(), &a_fty, &b_fty)
+                    .map(|InferOk { value, obligations }| {
+                        // FIXME(#32730) propagate obligations
+                        assert!(obligations.is_empty());
+                        value
+                    })?;
+
+                if a_def_id == b_def_id {
+                    // Same function, maybe the parameters match.
+                    let substs = self.commit_if_ok(|_| {
+                        self.lub(true, trace.clone(), &a_substs, &b_substs)
+                            .map(|InferOk { value, obligations }| {
+                                // FIXME(#32730) propagate obligations
+                                assert!(obligations.is_empty());
+                                value
+                            })
+                    });
+
+                    if let Ok(substs) = substs {
+                        // We have a LUB of prev_ty and new_ty, just return it.
+                        return Ok(self.tcx.mk_fn_def(a_def_id, substs, fty));
+                    }
+                }
+
+                // Reify both sides and return the reified fn pointer type.
+                for expr in exprs().into_iter().chain(Some(new)) {
+                    // No adjustments can produce a fn item, so this should never trip.
+                    assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
+                    self.write_adjustment(expr.id, AdjustReifyFnPointer);
+                }
+                return Ok(self.tcx.mk_fn_ptr(fty));
+            }
+            _ => {}
         }
-        Ok(ty)
-    })
-}
 
-/// Given some expressions, their known unified type and another expression,
-/// tries to unify the types, potentially inserting coercions on any of the
-/// provided expressions and returns their LUB (aka "common supertype").
-pub fn try_find_coercion_lub<'b, E, I>(&self,
-                                       origin: TypeOrigin,
-                                       exprs: E,
-                                       prev_ty: Ty<'tcx>,
-                                       new: &'b hir::Expr)
-                                       -> RelateResult<'tcx, Ty<'tcx>>
-    // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
-    where E: Fn() -> I,
-          I: IntoIterator<Item=&'b hir::Expr> {
+        let mut coerce = Coerce::new(self, origin);
+        coerce.use_lub = true;
 
-    let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
-    let new_ty = self.resolve_type_vars_with_obligations(self.expr_ty(new));
-    debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
+        // First try to coerce the new expression to the type of the previous ones,
+        // but only if the new expression has no coercion already applied to it.
+        let mut first_error = None;
+        if !self.tables.borrow().adjustments.contains_key(&new.id) {
+            let result = self.commit_if_ok(|_| {
+                apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
+            });
+            match result {
+                Ok((ty, adjustment)) => {
+                    if !adjustment.is_identity() {
+                        self.write_adjustment(new.id, adjustment);
+                    }
+                    return Ok(ty);
+                }
+                Err(e) => first_error = Some(e)
+            }
+        }
 
-    let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
+        // Then try to coerce the previous expressions to the type of the new one.
+        // This requires ensuring there are no coercions applied to *any* of the
+        // previous expressions, other than noop reborrows (ignoring lifetimes).
+        for expr in exprs() {
+            let noop = match self.tables.borrow().adjustments.get(&expr.id) {
+                Some(&AdjustDerefRef(AutoDerefRef {
+                    autoderefs: 1,
+                    autoref: Some(AutoPtr(_, mutbl_adj)),
+                    unsize: None
+                })) => match self.expr_ty(expr).sty {
+                    ty::TyRef(_, mt_orig) => {
+                        // Reborrow that we can safely ignore.
+                        mutbl_adj == mt_orig.mutbl
+                    }
+                    _ => false
+                },
+                Some(_) => false,
+                None => true
+            };
 
-    // Special-case that coercion alone cannot handle:
-    // Two function item types of differing IDs or Substs.
-    match (&prev_ty.sty, &new_ty.sty) {
-        (&ty::TyFnDef(a_def_id, a_substs, a_fty),
-         &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
-            // The signature must always match.
-            let fty = self.lub(true, trace.clone(), &a_fty, &b_fty)
-                .map(|InferOk { value, obligations }| {
-                    // FIXME(#32730) propagate obligations
-                    assert!(obligations.is_empty());
-                    value
-                })?;
-
-            if a_def_id == b_def_id {
-                // Same function, maybe the parameters match.
-                let substs = self.commit_if_ok(|_| {
-                    self.lub(true, trace.clone(), &a_substs, &b_substs)
+            if !noop {
+                return self.commit_if_ok(|_| {
+                    self.lub(true, trace.clone(), &prev_ty, &new_ty)
                         .map(|InferOk { value, obligations }| {
                             // FIXME(#32730) propagate obligations
                             assert!(obligations.is_empty());
                             value
                         })
                 });
+            }
+        }
 
-                if let Ok(substs) = substs {
-                    // We have a LUB of prev_ty and new_ty, just return it.
-                    return Ok(self.tcx.mk_fn_def(a_def_id, substs, fty));
+        match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
+            Err(_) => {
+                // Avoid giving strange errors on failed attempts.
+                if let Some(e) = first_error {
+                    Err(e)
+                } else {
+                    self.commit_if_ok(|_| {
+                        self.lub(true, trace, &prev_ty, &new_ty)
+                            .map(|InferOk { value, obligations }| {
+                                // FIXME(#32730) propagate obligations
+                                assert!(obligations.is_empty());
+                                value
+                            })
+                    })
                 }
             }
-
-            // Reify both sides and return the reified fn pointer type.
-            for expr in exprs().into_iter().chain(Some(new)) {
-                // No adjustments can produce a fn item, so this should never trip.
-                assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
-                self.write_adjustment(expr.id, AdjustReifyFnPointer);
-            }
-            return Ok(self.tcx.mk_fn_ptr(fty));
-        }
-        _ => {}
-    }
-
-    let mut coerce = Coerce::new(self, origin);
-    coerce.use_lub = true;
-
-    // First try to coerce the new expression to the type of the previous ones,
-    // but only if the new expression has no coercion already applied to it.
-    let mut first_error = None;
-    if !self.tables.borrow().adjustments.contains_key(&new.id) {
-        let result = self.commit_if_ok(|_| {
-            apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
-        });
-        match result {
             Ok((ty, adjustment)) => {
                 if !adjustment.is_identity() {
-                    self.write_adjustment(new.id, adjustment);
+                    for expr in exprs() {
+                        self.write_adjustment(expr.id, adjustment);
+                    }
                 }
-                return Ok(ty);
+                Ok(ty)
             }
-            Err(e) => first_error = Some(e)
-        }
-    }
-
-    // Then try to coerce the previous expressions to the type of the new one.
-    // This requires ensuring there are no coercions applied to *any* of the
-    // previous expressions, other than noop reborrows (ignoring lifetimes).
-    for expr in exprs() {
-        let noop = match self.tables.borrow().adjustments.get(&expr.id) {
-            Some(&AdjustDerefRef(AutoDerefRef {
-                autoderefs: 1,
-                autoref: Some(AutoPtr(_, mutbl_adj)),
-                unsize: None
-            })) => match self.expr_ty(expr).sty {
-                ty::TyRef(_, mt_orig) => {
-                    // Reborrow that we can safely ignore.
-                    mutbl_adj == mt_orig.mutbl
-                }
-                _ => false
-            },
-            Some(_) => false,
-            None => true
-        };
-
-        if !noop {
-            return self.commit_if_ok(|_| {
-                self.lub(true, trace.clone(), &prev_ty, &new_ty)
-                    .map(|InferOk { value, obligations }| {
-                        // FIXME(#32730) propagate obligations
-                        assert!(obligations.is_empty());
-                        value
-                    })
-            });
-        }
-    }
-
-    match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
-        Err(_) => {
-            // Avoid giving strange errors on failed attempts.
-            if let Some(e) = first_error {
-                Err(e)
-            } else {
-                self.commit_if_ok(|_| {
-                    self.lub(true, trace, &prev_ty, &new_ty)
-                        .map(|InferOk { value, obligations }| {
-                            // FIXME(#32730) propagate obligations
-                            assert!(obligations.is_empty());
-                            value
-                        })
-                })
-            }
-        }
-        Ok((ty, adjustment)) => {
-            if !adjustment.is_identity() {
-                for expr in exprs() {
-                    self.write_adjustment(expr.id, adjustment);
-                }
-            }
-            Ok(ty)
         }
     }
 }
-}
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 065425c86c7..7c8eb62b0e7 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -17,53 +17,53 @@ use syntax::codemap::Span;
 use rustc::hir;
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-// Requires that the two types unify, and prints an error message if
-// they don't.
-pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
-    let origin = TypeOrigin::Misc(sp);
-    match self.sub_types(false, origin, actual, expected) {
-        Ok(InferOk { obligations, .. }) => {
-            // FIXME(#32730) propagate obligations
-            assert!(obligations.is_empty());
-        },
-        Err(e) => {
-            self.report_mismatched_types(origin, expected, actual, e);
+    // Requires that the two types unify, and prints an error message if
+    // they don't.
+    pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
+        let origin = TypeOrigin::Misc(sp);
+        match self.sub_types(false, origin, actual, expected) {
+            Ok(InferOk { obligations, .. }) => {
+                // FIXME(#32730) propagate obligations
+                assert!(obligations.is_empty());
+            },
+            Err(e) => {
+                self.report_mismatched_types(origin, expected, actual, e);
+            }
+        }
+    }
+
+    pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
+        let origin = TypeOrigin::Misc(sp);
+        match self.eq_types(false, origin, actual, expected) {
+            Ok(InferOk { obligations, .. }) => {
+                // FIXME(#32730) propagate obligations
+                assert!(obligations.is_empty());
+            },
+            Err(e) => {
+                self.report_mismatched_types(origin, expected, actual, e);
+            }
+        }
+    }
+
+    // Checks that the type of `expr` can be coerced to `expected`.
+    pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) {
+        let expected = self.resolve_type_vars_with_obligations(expected);
+        if let Err(e) = self.try_coerce(expr, expected) {
+            let origin = TypeOrigin::Misc(expr.span);
+            let expr_ty = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
+            self.report_mismatched_types(origin, expected, expr_ty, e);
+        }
+    }
+
+    pub fn require_same_types(&self, span: Span, t1: Ty<'tcx>, t2: Ty<'tcx>, msg: &str)
+                              -> bool {
+        if let Err(err) = self.eq_types(false, TypeOrigin::Misc(span), t1, t2) {
+            let found_ty = self.resolve_type_vars_if_possible(&t1);
+            let expected_ty = self.resolve_type_vars_if_possible(&t2);
+            ::emit_type_err(self.tcx, span, found_ty, expected_ty, &err, msg);
+            false
+        } else {
+            true
         }
     }
 }
-
-pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
-    let origin = TypeOrigin::Misc(sp);
-    match self.eq_types(false, origin, actual, expected) {
-        Ok(InferOk { obligations, .. }) => {
-            // FIXME(#32730) propagate obligations
-            assert!(obligations.is_empty());
-        },
-        Err(e) => {
-            self.report_mismatched_types(origin, expected, actual, e);
-        }
-    }
-}
-
-// Checks that the type of `expr` can be coerced to `expected`.
-pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) {
-    let expected = self.resolve_type_vars_with_obligations(expected);
-    if let Err(e) = self.try_coerce(expr, expected) {
-        let origin = TypeOrigin::Misc(expr.span);
-        let expr_ty = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
-        self.report_mismatched_types(origin, expected, expr_ty, e);
-    }
-}
-
-pub fn require_same_types(&self, span: Span, t1: Ty<'tcx>, t2: Ty<'tcx>, msg: &str)
-                          -> bool {
-    if let Err(err) = self.eq_types(false, TypeOrigin::Misc(span), t1, t2) {
-        let found_ty = self.resolve_type_vars_if_possible(&t1);
-        let expected_ty = self.resolve_type_vars_if_possible(&t2);
-        ::emit_type_err(self.tcx, span, found_ty, expected_ty, &err, msg);
-        false
-    } else {
-        true
-    }
-}
-}
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 3360f9dab78..6faf6f415c2 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -53,23 +53,23 @@ struct InstantiatedMethodSig<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-pub fn confirm_method(&self,
-                      span: Span,
-                      self_expr: &'gcx hir::Expr,
-                      call_expr: &'gcx hir::Expr,
-                      unadjusted_self_ty: Ty<'tcx>,
-                      pick: probe::Pick<'tcx>,
-                      supplied_method_types: Vec<Ty<'tcx>>)
-                      -> ty::MethodCallee<'tcx>
-{
-    debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
-           unadjusted_self_ty,
-           pick,
-           supplied_method_types);
+    pub fn confirm_method(&self,
+                          span: Span,
+                          self_expr: &'gcx hir::Expr,
+                          call_expr: &'gcx hir::Expr,
+                          unadjusted_self_ty: Ty<'tcx>,
+                          pick: probe::Pick<'tcx>,
+                          supplied_method_types: Vec<Ty<'tcx>>)
+                          -> ty::MethodCallee<'tcx>
+    {
+        debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
+               unadjusted_self_ty,
+               pick,
+               supplied_method_types);
 
-    let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
-    confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types)
-}
+        let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
+        confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types)
+    }
 }
 
 impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index f30abbaba0e..f27ae181f77 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -79,311 +79,314 @@ pub enum CandidateSource {
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-/// Determines whether the type `self_ty` supports a method name `method_name` or not.
-pub fn method_exists(&self,
-                     span: Span,
-                     method_name: ast::Name,
-                     self_ty: ty::Ty<'tcx>,
-                     call_expr_id: ast::NodeId)
-                     -> bool
-{
-    let mode = probe::Mode::MethodCall;
-    match self.probe_method(span, mode, method_name, self_ty, call_expr_id) {
-        Ok(..) => true,
-        Err(NoMatch(..)) => false,
-        Err(Ambiguity(..)) => true,
-        Err(ClosureAmbiguity(..)) => true,
-        Err(PrivateMatch(..)) => true,
-    }
-}
-
-/// Performs method lookup. If lookup is successful, it will return the callee and store an
-/// appropriate adjustment for the self-expr. In some cases it may report an error (e.g., invoking
-/// the `drop` method).
-///
-/// # Arguments
-///
-/// Given a method call like `foo.bar::<T1,...Tn>(...)`:
-///
-/// * `fcx`:                   the surrounding `FnCtxt` (!)
-/// * `span`:                  the span for the method call
-/// * `method_name`:           the name of the method being called (`bar`)
-/// * `self_ty`:               the (unadjusted) type of the self expression (`foo`)
-/// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`)
-/// * `self_expr`:             the self expression (`foo`)
-pub fn lookup_method(&self,
-                     span: Span,
-                     method_name: ast::Name,
-                     self_ty: ty::Ty<'tcx>,
-                     supplied_method_types: Vec<ty::Ty<'tcx>>,
-                     call_expr: &'gcx hir::Expr,
-                     self_expr: &'gcx hir::Expr)
-                     -> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>>
-{
-    debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
-           method_name,
-           self_ty,
-           call_expr,
-           self_expr);
-
-    let mode = probe::Mode::MethodCall;
-    let self_ty = self.resolve_type_vars_if_possible(&self_ty);
-    let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?;
-
-    if let Some(import_id) = pick.import_id {
-        self.tcx.used_trait_imports.borrow_mut().insert(import_id);
-    }
-
-    Ok(self.confirm_method(span, self_expr, call_expr, self_ty, pick, supplied_method_types))
-}
-
-pub fn lookup_method_in_trait(&self,
-                              span: Span,
-                              self_expr: Option<&hir::Expr>,
-                              m_name: ast::Name,
-                              trait_def_id: DefId,
-                              self_ty: ty::Ty<'tcx>,
-                              opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
-                              -> Option<ty::MethodCallee<'tcx>>
-{
-    self.lookup_method_in_trait_adjusted(span, self_expr, m_name, trait_def_id,
-                                         0, false, self_ty, opt_input_types)
-}
-
-/// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of
-/// what the normal probe/confirm path does. In particular, it doesn't really do any probing: it
-/// simply constructs an obligation for a particular trait with the given self-type and checks
-/// whether that trait is implemented.
-///
-/// FIXME(#18741) -- It seems likely that we can consolidate some of this code with the other
-/// method-lookup code. In particular, autoderef on index is basically identical to autoderef with
-/// normal probes, except that the test also looks for built-in indexing. Also, the second half of
-/// this method is basically the same as confirmation.
-pub fn lookup_method_in_trait_adjusted(&self,
-                                       span: Span,
-                                       self_expr: Option<&hir::Expr>,
-                                       m_name: ast::Name,
-                                       trait_def_id: DefId,
-                                       autoderefs: usize,
-                                       unsize: bool,
-                                       self_ty: ty::Ty<'tcx>,
-                                       opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
-                                       -> Option<ty::MethodCallee<'tcx>>
-{
-    debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, m_name={}, trait_def_id={:?})",
-           self_ty,
-           self_expr,
-           m_name,
-           trait_def_id);
-
-    let trait_def = self.tcx.lookup_trait_def(trait_def_id);
-
-    let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace);
-    let expected_number_of_input_types = type_parameter_defs.len();
-
-    assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0);
-    assert!(trait_def.generics.regions.is_empty());
-
-    // Construct a trait-reference `self_ty : Trait<input_tys>`
-    let mut substs = subst::Substs::new_trait(Vec::new(), Vec::new(), self_ty);
-
-    match opt_input_types {
-        Some(input_types) => {
-            assert_eq!(expected_number_of_input_types, input_types.len());
-            substs.types.replace(subst::ParamSpace::TypeSpace, input_types);
-        }
-
-        None => {
-            self.type_vars_for_defs(
-                span,
-                subst::ParamSpace::TypeSpace,
-                &mut substs,
-                type_parameter_defs);
+    /// Determines whether the type `self_ty` supports a method name `method_name` or not.
+    pub fn method_exists(&self,
+                         span: Span,
+                         method_name: ast::Name,
+                         self_ty: ty::Ty<'tcx>,
+                         call_expr_id: ast::NodeId)
+                         -> bool
+    {
+        let mode = probe::Mode::MethodCall;
+        match self.probe_method(span, mode, method_name, self_ty, call_expr_id) {
+            Ok(..) => true,
+            Err(NoMatch(..)) => false,
+            Err(Ambiguity(..)) => true,
+            Err(ClosureAmbiguity(..)) => true,
+            Err(PrivateMatch(..)) => true,
         }
     }
 
-    let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx.mk_substs(substs));
+    /// Performs method lookup. If lookup is successful, it will return the callee
+    /// and store an appropriate adjustment for the self-expr. In some cases it may
+    /// report an error (e.g., invoking the `drop` method).
+    ///
+    /// # Arguments
+    ///
+    /// Given a method call like `foo.bar::<T1,...Tn>(...)`:
+    ///
+    /// * `fcx`:                   the surrounding `FnCtxt` (!)
+    /// * `span`:                  the span for the method call
+    /// * `method_name`:           the name of the method being called (`bar`)
+    /// * `self_ty`:               the (unadjusted) type of the self expression (`foo`)
+    /// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`)
+    /// * `self_expr`:             the self expression (`foo`)
+    pub fn lookup_method(&self,
+                         span: Span,
+                         method_name: ast::Name,
+                         self_ty: ty::Ty<'tcx>,
+                         supplied_method_types: Vec<ty::Ty<'tcx>>,
+                         call_expr: &'gcx hir::Expr,
+                         self_expr: &'gcx hir::Expr)
+                         -> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>>
+    {
+        debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
+               method_name,
+               self_ty,
+               call_expr,
+               self_expr);
 
-    // Construct an obligation
-    let poly_trait_ref = trait_ref.to_poly_trait_ref();
-    let obligation = traits::Obligation::misc(span,
-                                              self.body_id,
-                                              poly_trait_ref.to_predicate());
+        let mode = probe::Mode::MethodCall;
+        let self_ty = self.resolve_type_vars_if_possible(&self_ty);
+        let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?;
 
-    // Now we want to know if this can be matched
-    let mut selcx = traits::SelectionContext::new(self);
-    if !selcx.evaluate_obligation(&obligation) {
-        debug!("--> Cannot match obligation");
-        return None; // Cannot be matched, no such method resolution is possible.
+        if let Some(import_id) = pick.import_id {
+            self.tcx.used_trait_imports.borrow_mut().insert(import_id);
+        }
+
+        Ok(self.confirm_method(span, self_expr, call_expr, self_ty, pick, supplied_method_types))
     }
 
-    // Trait must have a method named `m_name` and it should not have
-    // type parameters or early-bound regions.
-    let tcx = self.tcx;
-    let method_item = self.trait_item(trait_def_id, m_name).unwrap();
-    let method_ty = method_item.as_opt_method().unwrap();
-    assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
-    assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
+    pub fn lookup_method_in_trait(&self,
+                                  span: Span,
+                                  self_expr: Option<&hir::Expr>,
+                                  m_name: ast::Name,
+                                  trait_def_id: DefId,
+                                  self_ty: ty::Ty<'tcx>,
+                                  opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
+                                  -> Option<ty::MethodCallee<'tcx>>
+    {
+        self.lookup_method_in_trait_adjusted(span, self_expr, m_name, trait_def_id,
+                                             0, false, self_ty, opt_input_types)
+    }
 
-    debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}",
-           method_item, method_ty);
+    /// `lookup_in_trait_adjusted` is used for overloaded operators.
+    /// It does a very narrow slice of what the normal probe/confirm path does.
+    /// In particular, it doesn't really do any probing: it simply constructs
+    /// an obligation for aparticular trait with the given self-type and checks
+    /// whether that trait is implemented.
+    ///
+    /// FIXME(#18741) -- It seems likely that we can consolidate some of this
+    /// code with the other method-lookup code. In particular, autoderef on
+    /// index is basically identical to autoderef with normal probes, except
+    /// that the test also looks for built-in indexing. Also, the second half of
+    /// this method is basically the same as confirmation.
+    pub fn lookup_method_in_trait_adjusted(&self,
+                                           span: Span,
+                                           self_expr: Option<&hir::Expr>,
+                                           m_name: ast::Name,
+                                           trait_def_id: DefId,
+                                           autoderefs: usize,
+                                           unsize: bool,
+                                           self_ty: ty::Ty<'tcx>,
+                                           opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
+                                           -> Option<ty::MethodCallee<'tcx>>
+    {
+        debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, \
+                m_name={}, trait_def_id={:?})",
+               self_ty,
+               self_expr,
+               m_name,
+               trait_def_id);
 
-    // Instantiate late-bound regions and substitute the trait
-    // parameters into the method type to get the actual method type.
-    //
-    // NB: Instantiate late-bound regions first so that
-    // `instantiate_type_scheme` can normalize associated types that
-    // may reference those regions.
-    let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
-                                                                infer::FnCall,
-                                                                &method_ty.fty.sig).0;
-    let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
-    let transformed_self_ty = fn_sig.inputs[0];
-    let def_id = method_item.def_id();
-    let fty = tcx.mk_fn_def(def_id, trait_ref.substs,
-                            tcx.mk_bare_fn(ty::BareFnTy {
-        sig: ty::Binder(fn_sig),
-        unsafety: method_ty.fty.unsafety,
-        abi: method_ty.fty.abi.clone(),
-    }));
+        let trait_def = self.tcx.lookup_trait_def(trait_def_id);
 
-    debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}",
-           fty,
-           obligation);
+        let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace);
+        let expected_number_of_input_types = type_parameter_defs.len();
 
-    // Register obligations for the parameters.  This will include the
-    // `Self` parameter, which in turn has a bound of the main trait,
-    // so this also effectively registers `obligation` as well.  (We
-    // used to register `obligation` explicitly, but that resulted in
-    // double error messages being reported.)
-    //
-    // Note that as the method comes from a trait, it should not have
-    // any late-bound regions appearing in its bounds.
-    let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates);
-    assert!(!method_bounds.has_escaping_regions());
-    self.add_obligations_for_parameters(
-        traits::ObligationCause::misc(span, self.body_id),
-        &method_bounds);
+        assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0);
+        assert!(trait_def.generics.regions.is_empty());
 
-    // Also register an obligation for the method type being well-formed.
-    self.register_wf_obligation(fty, span, traits::MiscObligation);
+        // Construct a trait-reference `self_ty : Trait<input_tys>`
+        let mut substs = subst::Substs::new_trait(Vec::new(), Vec::new(), self_ty);
 
-    // FIXME(#18653) -- Try to resolve obligations, giving us more
-    // typing information, which can sometimes be needed to avoid
-    // pathological region inference failures.
-    self.select_obligations_where_possible();
+        match opt_input_types {
+            Some(input_types) => {
+                assert_eq!(expected_number_of_input_types, input_types.len());
+                substs.types.replace(subst::ParamSpace::TypeSpace, input_types);
+            }
 
-    // Insert any adjustments needed (always an autoref of some mutability).
-    match self_expr {
-        None => { }
+            None => {
+                self.type_vars_for_defs(
+                    span,
+                    subst::ParamSpace::TypeSpace,
+                    &mut substs,
+                    type_parameter_defs);
+            }
+        }
 
-        Some(self_expr) => {
-            debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
-                   (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})",
-                   self_expr.id, autoderefs, unsize,
-                   method_ty.explicit_self);
+        let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx.mk_substs(substs));
 
-            match method_ty.explicit_self {
-                ty::ExplicitSelfCategory::ByValue => {
-                    // Trait method is fn(self), no transformation needed.
-                    assert!(!unsize);
-                    self.write_autoderef_adjustment(self_expr.id, autoderefs);
-                }
+        // Construct an obligation
+        let poly_trait_ref = trait_ref.to_poly_trait_ref();
+        let obligation = traits::Obligation::misc(span,
+                                                  self.body_id,
+                                                  poly_trait_ref.to_predicate());
 
-                ty::ExplicitSelfCategory::ByReference(..) => {
-                    // Trait method is fn(&self) or fn(&mut self), need an
-                    // autoref. Pull the region etc out of the type of first argument.
-                    match transformed_self_ty.sty {
-                        ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => {
-                            self.write_adjustment(self_expr.id,
-                                AdjustDerefRef(AutoDerefRef {
-                                    autoderefs: autoderefs,
-                                    autoref: Some(AutoPtr(region, mutbl)),
-                                    unsize: if unsize {
-                                        Some(transformed_self_ty)
-                                    } else {
-                                        None
-                                    }
-                                }));
-                        }
+        // Now we want to know if this can be matched
+        let mut selcx = traits::SelectionContext::new(self);
+        if !selcx.evaluate_obligation(&obligation) {
+            debug!("--> Cannot match obligation");
+            return None; // Cannot be matched, no such method resolution is possible.
+        }
 
-                        _ => {
-                            span_bug!(
-                                span,
-                                "trait method is &self but first arg is: {}",
-                                transformed_self_ty);
+        // Trait must have a method named `m_name` and it should not have
+        // type parameters or early-bound regions.
+        let tcx = self.tcx;
+        let method_item = self.trait_item(trait_def_id, m_name).unwrap();
+        let method_ty = method_item.as_opt_method().unwrap();
+        assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
+        assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
+
+        debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}",
+               method_item, method_ty);
+
+        // Instantiate late-bound regions and substitute the trait
+        // parameters into the method type to get the actual method type.
+        //
+        // NB: Instantiate late-bound regions first so that
+        // `instantiate_type_scheme` can normalize associated types that
+        // may reference those regions.
+        let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
+                                                                    infer::FnCall,
+                                                                    &method_ty.fty.sig).0;
+        let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
+        let transformed_self_ty = fn_sig.inputs[0];
+        let def_id = method_item.def_id();
+        let fty = tcx.mk_fn_def(def_id, trait_ref.substs,
+                                tcx.mk_bare_fn(ty::BareFnTy {
+            sig: ty::Binder(fn_sig),
+            unsafety: method_ty.fty.unsafety,
+            abi: method_ty.fty.abi.clone(),
+        }));
+
+        debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}",
+               fty,
+               obligation);
+
+        // Register obligations for the parameters.  This will include the
+        // `Self` parameter, which in turn has a bound of the main trait,
+        // so this also effectively registers `obligation` as well.  (We
+        // used to register `obligation` explicitly, but that resulted in
+        // double error messages being reported.)
+        //
+        // Note that as the method comes from a trait, it should not have
+        // any late-bound regions appearing in its bounds.
+        let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates);
+        assert!(!method_bounds.has_escaping_regions());
+        self.add_obligations_for_parameters(
+            traits::ObligationCause::misc(span, self.body_id),
+            &method_bounds);
+
+        // Also register an obligation for the method type being well-formed.
+        self.register_wf_obligation(fty, span, traits::MiscObligation);
+
+        // FIXME(#18653) -- Try to resolve obligations, giving us more
+        // typing information, which can sometimes be needed to avoid
+        // pathological region inference failures.
+        self.select_obligations_where_possible();
+
+        // Insert any adjustments needed (always an autoref of some mutability).
+        match self_expr {
+            None => { }
+
+            Some(self_expr) => {
+                debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
+                       (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})",
+                       self_expr.id, autoderefs, unsize,
+                       method_ty.explicit_self);
+
+                match method_ty.explicit_self {
+                    ty::ExplicitSelfCategory::ByValue => {
+                        // Trait method is fn(self), no transformation needed.
+                        assert!(!unsize);
+                        self.write_autoderef_adjustment(self_expr.id, autoderefs);
+                    }
+
+                    ty::ExplicitSelfCategory::ByReference(..) => {
+                        // Trait method is fn(&self) or fn(&mut self), need an
+                        // autoref. Pull the region etc out of the type of first argument.
+                        match transformed_self_ty.sty {
+                            ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => {
+                                self.write_adjustment(self_expr.id,
+                                    AdjustDerefRef(AutoDerefRef {
+                                        autoderefs: autoderefs,
+                                        autoref: Some(AutoPtr(region, mutbl)),
+                                        unsize: if unsize {
+                                            Some(transformed_self_ty)
+                                        } else {
+                                            None
+                                        }
+                                    }));
+                            }
+
+                            _ => {
+                                span_bug!(
+                                    span,
+                                    "trait method is &self but first arg is: {}",
+                                    transformed_self_ty);
+                            }
                         }
                     }
-                }
 
-                _ => {
-                    span_bug!(
-                        span,
-                        "unexpected explicit self type in operator method: {:?}",
-                        method_ty.explicit_self);
+                    _ => {
+                        span_bug!(
+                            span,
+                            "unexpected explicit self type in operator method: {:?}",
+                            method_ty.explicit_self);
+                    }
                 }
             }
         }
+
+        let callee = ty::MethodCallee {
+            def_id: def_id,
+            ty: fty,
+            substs: trait_ref.substs
+        };
+
+        debug!("callee = {:?}", callee);
+
+        Some(callee)
     }
 
-    let callee = ty::MethodCallee {
-        def_id: def_id,
-        ty: fty,
-        substs: trait_ref.substs
-    };
+    pub fn resolve_ufcs(&self,
+                        span: Span,
+                        method_name: ast::Name,
+                        self_ty: ty::Ty<'tcx>,
+                        expr_id: ast::NodeId)
+                        -> Result<Def, MethodError<'tcx>>
+    {
+        let mode = probe::Mode::Path;
+        let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
 
-    debug!("callee = {:?}", callee);
-
-    Some(callee)
-}
-
-pub fn resolve_ufcs(&self,
-                    span: Span,
-                    method_name: ast::Name,
-                    self_ty: ty::Ty<'tcx>,
-                    expr_id: ast::NodeId)
-                    -> Result<Def, MethodError<'tcx>>
-{
-    let mode = probe::Mode::Path;
-    let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
-
-    if let Some(import_id) = pick.import_id {
-        self.tcx.used_trait_imports.borrow_mut().insert(import_id);
-    }
-
-    let def = pick.item.def();
-    if let probe::InherentImplPick = pick.kind {
-        if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx.map) {
-            let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str());
-            self.tcx.sess.span_err(span, &msg);
+        if let Some(import_id) = pick.import_id {
+            self.tcx.used_trait_imports.borrow_mut().insert(import_id);
         }
+
+        let def = pick.item.def();
+        if let probe::InherentImplPick = pick.kind {
+            if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx.map) {
+                let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str());
+                self.tcx.sess.span_err(span, &msg);
+            }
+        }
+        Ok(def)
     }
-    Ok(def)
-}
 
-/// Find item with name `item_name` defined in `trait_def_id`
-/// and return it, or `None`, if no such item.
-pub fn trait_item(&self,
-                  trait_def_id: DefId,
-                  item_name: ast::Name)
-                  -> Option<ty::ImplOrTraitItem<'tcx>>
-{
-    let trait_items = self.tcx.trait_items(trait_def_id);
-    trait_items.iter()
-               .find(|item| item.name() == item_name)
-               .cloned()
-}
+    /// Find item with name `item_name` defined in `trait_def_id`
+    /// and return it, or `None`, if no such item.
+    pub fn trait_item(&self,
+                      trait_def_id: DefId,
+                      item_name: ast::Name)
+                      -> Option<ty::ImplOrTraitItem<'tcx>>
+    {
+        let trait_items = self.tcx.trait_items(trait_def_id);
+        trait_items.iter()
+                   .find(|item| item.name() == item_name)
+                   .cloned()
+    }
 
-pub fn impl_item(&self,
-                 impl_def_id: DefId,
-                 item_name: ast::Name)
-                 -> Option<ty::ImplOrTraitItem<'tcx>>
-{
-    let impl_items = self.tcx.impl_items.borrow();
-    let impl_items = impl_items.get(&impl_def_id).unwrap();
-    impl_items
-        .iter()
-        .map(|&did| self.tcx.impl_or_trait_item(did.def_id()))
-        .find(|m| m.name() == item_name)
-}
+    pub fn impl_item(&self,
+                     impl_def_id: DefId,
+                     item_name: ast::Name)
+                     -> Option<ty::ImplOrTraitItem<'tcx>>
+    {
+        let impl_items = self.tcx.impl_items.borrow();
+        let impl_items = impl_items.get(&impl_def_id).unwrap();
+        impl_items
+            .iter()
+            .map(|&did| self.tcx.impl_or_trait_item(did.def_id()))
+            .find(|m| m.name() == item_name)
+    }
 }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 8ce92892e9a..08c04122517 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -137,108 +137,108 @@ pub enum Mode {
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-pub fn probe_method(&self,
-                    span: Span,
-                    mode: Mode,
-                    item_name: ast::Name,
-                    self_ty: Ty<'tcx>,
-                    scope_expr_id: ast::NodeId)
-                    -> PickResult<'tcx>
-{
-    debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})",
-           self_ty,
-           item_name,
-           scope_expr_id);
+    pub fn probe_method(&self,
+                        span: Span,
+                        mode: Mode,
+                        item_name: ast::Name,
+                        self_ty: Ty<'tcx>,
+                        scope_expr_id: ast::NodeId)
+                        -> PickResult<'tcx>
+    {
+        debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})",
+               self_ty,
+               item_name,
+               scope_expr_id);
 
-    // FIXME(#18741) -- right now, creating the steps involves evaluating the
-    // `*` operator, which registers obligations that then escape into
-    // the global fulfillment context and thus has global
-    // side-effects. This is a bit of a pain to refactor. So just let
-    // it ride, although it's really not great, and in fact could I
-    // think cause spurious errors. Really though this part should
-    // take place in the `self.probe` below.
-    let steps = if mode == Mode::MethodCall {
-        match self.create_steps(span, self_ty) {
-            Some(steps) => steps,
-            None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(),
-                                                                    Vec::new(), mode))),
-        }
-    } else {
-        vec![CandidateStep {
-            self_ty: self_ty,
-            autoderefs: 0,
-            unsize: false
-        }]
-    };
-
-    // Create a list of simplified self types, if we can.
-    let mut simplified_steps = Vec::new();
-    for step in &steps {
-        match ty::fast_reject::simplify_type(self.tcx, step.self_ty, true) {
-            None => { break; }
-            Some(simplified_type) => { simplified_steps.push(simplified_type); }
-        }
-    }
-    let opt_simplified_steps =
-        if simplified_steps.len() < steps.len() {
-            None // failed to convert at least one of the steps
+        // FIXME(#18741) -- right now, creating the steps involves evaluating the
+        // `*` operator, which registers obligations that then escape into
+        // the global fulfillment context and thus has global
+        // side-effects. This is a bit of a pain to refactor. So just let
+        // it ride, although it's really not great, and in fact could I
+        // think cause spurious errors. Really though this part should
+        // take place in the `self.probe` below.
+        let steps = if mode == Mode::MethodCall {
+            match self.create_steps(span, self_ty) {
+                Some(steps) => steps,
+                None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(),
+                                                                        Vec::new(), mode))),
+            }
         } else {
-            Some(simplified_steps)
+            vec![CandidateStep {
+                self_ty: self_ty,
+                autoderefs: 0,
+                unsize: false
+            }]
         };
 
-    debug!("ProbeContext: steps for self_ty={:?} are {:?}",
-           self_ty,
-           steps);
-
-    // this creates one big transaction so that all type variables etc
-    // that we create during the probe process are removed later
-    self.probe(|_| {
-        let mut probe_cx = ProbeContext::new(self,
-                                             span,
-                                             mode,
-                                             item_name,
-                                             steps,
-                                             opt_simplified_steps);
-        probe_cx.assemble_inherent_candidates();
-        probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?;
-        probe_cx.pick()
-    })
-}
-
-fn create_steps(&self,
-                span: Span,
-                self_ty: Ty<'tcx>)
-                -> Option<Vec<CandidateStep<'tcx>>> {
-    let mut steps = Vec::new();
-
-    let (final_ty, dereferences, _) = self.autoderef(span,
-                                                     self_ty,
-                                                     || None,
-                                                     UnresolvedTypeAction::Error,
-                                                     NoPreference,
-                                                     |t, d| {
-        steps.push(CandidateStep {
-            self_ty: t,
-            autoderefs: d,
-            unsize: false
-        });
-        None::<()> // keep iterating until we can't anymore
-    });
-
-    match final_ty.sty {
-        ty::TyArray(elem_ty, _) => {
-            steps.push(CandidateStep {
-                self_ty: self.tcx.mk_slice(elem_ty),
-                autoderefs: dereferences,
-                unsize: true
-            });
+        // Create a list of simplified self types, if we can.
+        let mut simplified_steps = Vec::new();
+        for step in &steps {
+            match ty::fast_reject::simplify_type(self.tcx, step.self_ty, true) {
+                None => { break; }
+                Some(simplified_type) => { simplified_steps.push(simplified_type); }
+            }
         }
-        ty::TyError => return None,
-        _ => (),
+        let opt_simplified_steps =
+            if simplified_steps.len() < steps.len() {
+                None // failed to convert at least one of the steps
+            } else {
+                Some(simplified_steps)
+            };
+
+        debug!("ProbeContext: steps for self_ty={:?} are {:?}",
+               self_ty,
+               steps);
+
+        // this creates one big transaction so that all type variables etc
+        // that we create during the probe process are removed later
+        self.probe(|_| {
+            let mut probe_cx = ProbeContext::new(self,
+                                                 span,
+                                                 mode,
+                                                 item_name,
+                                                 steps,
+                                                 opt_simplified_steps);
+            probe_cx.assemble_inherent_candidates();
+            probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?;
+            probe_cx.pick()
+        })
     }
 
-    Some(steps)
-}
+    fn create_steps(&self,
+                    span: Span,
+                    self_ty: Ty<'tcx>)
+                    -> Option<Vec<CandidateStep<'tcx>>> {
+        let mut steps = Vec::new();
+
+        let (final_ty, dereferences, _) = self.autoderef(span,
+                                                         self_ty,
+                                                         || None,
+                                                         UnresolvedTypeAction::Error,
+                                                         NoPreference,
+                                                         |t, d| {
+            steps.push(CandidateStep {
+                self_ty: t,
+                autoderefs: d,
+                unsize: false
+            });
+            None::<()> // keep iterating until we can't anymore
+        });
+
+        match final_ty.sty {
+            ty::TyArray(elem_ty, _) => {
+                steps.push(CandidateStep {
+                    self_ty: self.tcx.mk_slice(elem_ty),
+                    autoderefs: dereferences,
+                    unsize: true
+                });
+            }
+            ty::TyError => return None,
+            _ => (),
+        }
+
+        Some(steps)
+    }
 }
 
 impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index ed60f9b6e7c..540af8b04bf 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -40,353 +40,353 @@ use super::{MethodError, NoMatchData, CandidateSource};
 use super::probe::Mode;
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool {
-    let tcx = self.tcx;
-    match ty.sty {
-        // Not all of these (e.g. unsafe fns) implement FnOnce
-        // so we look for these beforehand
-        ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => true,
-        // If it's not a simple function, look for things which implement FnOnce
-        _ => {
-            if let Ok(fn_once_trait_did) =
-                    tcx.lang_items.require(FnOnceTraitLangItem) {
-                let (_, _, opt_is_fn) = self.autoderef(span,
-                                                       ty,
-                                                       || None,
-                                                       UnresolvedTypeAction::Ignore,
-                                                       LvaluePreference::NoPreference,
-                                                       |ty, _| {
-                    self.probe(|_| {
-                        let fn_once_substs =
-                            Substs::new_trait(vec![self.next_ty_var()], vec![], ty);
-                        let trait_ref =
-                            ty::TraitRef::new(fn_once_trait_did,
-                                              tcx.mk_substs(fn_once_substs));
-                        let poly_trait_ref = trait_ref.to_poly_trait_ref();
-                        let obligation = Obligation::misc(span,
-                                                          self.body_id,
-                                                          poly_trait_ref
-                                                             .to_predicate());
-                        let mut selcx = SelectionContext::new(self);
+    fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool {
+        let tcx = self.tcx;
+        match ty.sty {
+            // Not all of these (e.g. unsafe fns) implement FnOnce
+            // so we look for these beforehand
+            ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => true,
+            // If it's not a simple function, look for things which implement FnOnce
+            _ => {
+                if let Ok(fn_once_trait_did) =
+                        tcx.lang_items.require(FnOnceTraitLangItem) {
+                    let (_, _, opt_is_fn) = self.autoderef(span,
+                                                           ty,
+                                                           || None,
+                                                           UnresolvedTypeAction::Ignore,
+                                                           LvaluePreference::NoPreference,
+                                                           |ty, _| {
+                        self.probe(|_| {
+                            let fn_once_substs =
+                                Substs::new_trait(vec![self.next_ty_var()], vec![], ty);
+                            let trait_ref =
+                                ty::TraitRef::new(fn_once_trait_did,
+                                                  tcx.mk_substs(fn_once_substs));
+                            let poly_trait_ref = trait_ref.to_poly_trait_ref();
+                            let obligation = Obligation::misc(span,
+                                                              self.body_id,
+                                                              poly_trait_ref
+                                                                 .to_predicate());
+                            let mut selcx = SelectionContext::new(self);
 
-                        if selcx.evaluate_obligation(&obligation) {
-                            Some(())
-                        } else {
-                            None
-                        }
-                    })
-                });
-
-                opt_is_fn.is_some()
-            } else {
-                false
-            }
-        }
-    }
-}
-pub fn report_method_error(&self,
-                           span: Span,
-                           rcvr_ty: Ty<'tcx>,
-                           item_name: ast::Name,
-                           rcvr_expr: Option<&hir::Expr>,
-                           error: MethodError<'tcx>)
-{
-    // avoid suggestions when we don't know what's going on.
-    if rcvr_ty.references_error() {
-        return
-    }
-
-    let report_candidates = |err: &mut DiagnosticBuilder,
-                             mut sources: Vec<CandidateSource>| {
-
-        sources.sort();
-        sources.dedup();
-
-        for (idx, source) in sources.iter().enumerate() {
-            match *source {
-                CandidateSource::ImplSource(impl_did) => {
-                    // Provide the best span we can. Use the item, if local to crate, else
-                    // the impl, if local to crate (item may be defaulted), else nothing.
-                    let item = self.impl_item(impl_did, item_name)
-                        .or_else(|| {
-                            self.trait_item(
-                                self.tcx.impl_trait_ref(impl_did).unwrap().def_id,
-
-                                item_name
-                            )
-                        }).unwrap();
-                    let note_span = self.tcx.map.span_if_local(item.def_id()).or_else(|| {
-                        self.tcx.map.span_if_local(impl_did)
+                            if selcx.evaluate_obligation(&obligation) {
+                                Some(())
+                            } else {
+                                None
+                            }
+                        })
                     });
 
-                    let impl_ty = self.impl_self_ty(span, impl_did).ty;
-
-                    let insertion = match self.tcx.impl_trait_ref(impl_did) {
-                        None => format!(""),
-                        Some(trait_ref) => {
-                            format!(" of the trait `{}`",
-                                    self.tcx.item_path_str(trait_ref.def_id))
-                        }
-                    };
-
-                    let note_str = format!("candidate #{} is defined in an impl{} \
-                                            for the type `{}`",
-                                           idx + 1,
-                                           insertion,
-                                           impl_ty);
-                    if let Some(note_span) = note_span {
-                        // We have a span pointing to the method. Show note with snippet.
-                        err.span_note(note_span, &note_str);
-                    } else {
-                        err.note(&note_str);
-                    }
-                }
-                CandidateSource::TraitSource(trait_did) => {
-                    let item = self.trait_item(trait_did, item_name).unwrap();
-                    let item_span = self.tcx.map.def_id_span(item.def_id(), span);
-                    span_note!(err, item_span,
-                               "candidate #{} is defined in the trait `{}`",
-                               idx + 1,
-                               self.tcx.item_path_str(trait_did));
+                    opt_is_fn.is_some()
+                } else {
+                    false
                 }
             }
         }
-    };
-
-    match error {
-        MethodError::NoMatch(NoMatchData { static_candidates: static_sources,
-                                           unsatisfied_predicates,
-                                           out_of_scope_traits,
-                                           mode, .. }) => {
-            let tcx = self.tcx;
-
-            let mut err = self.type_error_struct(
-                span,
-                |actual| {
-                    format!("no {} named `{}` found for type `{}` \
-                             in the current scope",
-                            if mode == Mode::MethodCall { "method" }
-                            else { "associated item" },
-                            item_name,
-                            actual)
-                },
-                rcvr_ty,
-                None);
-
-            // If the item has the name of a field, give a help note
-            if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) {
-                if let Some(field) = def.struct_variant().find_field_named(item_name) {
-                    let expr_string = match tcx.sess.codemap().span_to_snippet(expr.span) {
-                        Ok(expr_string) => expr_string,
-                        _ => "s".into() // Default to a generic placeholder for the
-                                        // expression when we can't generate a string
-                                        // snippet
-                    };
-
-                    let field_ty = field.ty(tcx, substs);
-
-                    if self.is_fn_ty(&field_ty, span) {
-                        err.span_note(span,
-                                      &format!("use `({0}.{1})(...)` if you meant to call \
-                                               the function stored in the `{1}` field",
-                                               expr_string, item_name));
-                    } else {
-                        err.span_note(span, &format!("did you mean to write `{0}.{1}`?",
-                                                     expr_string, item_name));
-                    }
-                }
-            }
-
-            if self.is_fn_ty(&rcvr_ty, span) {
-                macro_rules! report_function {
-                    ($span:expr, $name:expr) => {
-                        err.note(&format!("{} is a function, perhaps you wish to call it",
-                                     $name));
-                    }
-                }
-
-                if let Some(expr) = rcvr_expr {
-                    if let Ok (expr_string) = tcx.sess.codemap().span_to_snippet(expr.span) {
-                        report_function!(expr.span, expr_string);
-                    }
-                    else if let Expr_::ExprPath(_, path) = expr.node.clone() {
-                        if let Some(segment) = path.segments.last() {
-                            report_function!(expr.span, segment.identifier.name);
-                        }
-                    }
-                }
-            }
-
-            if !static_sources.is_empty() {
-                err.note(
-                    "found the following associated functions; to be used as \
-                     methods, functions must have a `self` parameter");
-
-                report_candidates(&mut err, static_sources);
-            }
-
-            if !unsatisfied_predicates.is_empty() {
-                let bound_list = unsatisfied_predicates.iter()
-                    .map(|p| format!("`{} : {}`",
-                                     p.self_ty(),
-                                     p))
-                    .collect::<Vec<_>>()
-                    .join(", ");
-                err.note(
-                    &format!("the method `{}` exists but the \
-                             following trait bounds were not satisfied: {}",
-                             item_name,
-                             bound_list));
-            }
-
-            self.suggest_traits_to_import(&mut err, span, rcvr_ty, item_name,
-                                          rcvr_expr, out_of_scope_traits);
-            err.emit();
-        }
-
-        MethodError::Ambiguity(sources) => {
-            let mut err = struct_span_err!(self.sess(), span, E0034,
-                                           "multiple applicable items in scope");
-
-            report_candidates(&mut err, sources);
-            err.emit();
-        }
-
-        MethodError::ClosureAmbiguity(trait_def_id) => {
-            let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \
-                               invoked on this closure as we have not yet inferred what \
-                               kind of closure it is",
-                               item_name,
-                               self.tcx.item_path_str(trait_def_id));
-            let msg = if let Some(callee) = rcvr_expr {
-                format!("{}; use overloaded call notation instead (e.g., `{}()`)",
-                        msg, pprust::expr_to_string(callee))
-            } else {
-                msg
-            };
-            self.sess().span_err(span, &msg);
-        }
-
-        MethodError::PrivateMatch(def) => {
-            let msg = format!("{} `{}` is private", def.kind_name(), item_name);
-            self.tcx.sess.span_err(span, &msg);
-        }
     }
-}
+    pub fn report_method_error(&self,
+                               span: Span,
+                               rcvr_ty: Ty<'tcx>,
+                               item_name: ast::Name,
+                               rcvr_expr: Option<&hir::Expr>,
+                               error: MethodError<'tcx>)
+    {
+        // avoid suggestions when we don't know what's going on.
+        if rcvr_ty.references_error() {
+            return
+        }
 
-fn suggest_traits_to_import(&self,
-                            err: &mut DiagnosticBuilder,
+        let report_candidates = |err: &mut DiagnosticBuilder,
+                                 mut sources: Vec<CandidateSource>| {
+
+            sources.sort();
+            sources.dedup();
+
+            for (idx, source) in sources.iter().enumerate() {
+                match *source {
+                    CandidateSource::ImplSource(impl_did) => {
+                        // Provide the best span we can. Use the item, if local to crate, else
+                        // the impl, if local to crate (item may be defaulted), else nothing.
+                        let item = self.impl_item(impl_did, item_name)
+                            .or_else(|| {
+                                self.trait_item(
+                                    self.tcx.impl_trait_ref(impl_did).unwrap().def_id,
+
+                                    item_name
+                                )
+                            }).unwrap();
+                        let note_span = self.tcx.map.span_if_local(item.def_id()).or_else(|| {
+                            self.tcx.map.span_if_local(impl_did)
+                        });
+
+                        let impl_ty = self.impl_self_ty(span, impl_did).ty;
+
+                        let insertion = match self.tcx.impl_trait_ref(impl_did) {
+                            None => format!(""),
+                            Some(trait_ref) => {
+                                format!(" of the trait `{}`",
+                                        self.tcx.item_path_str(trait_ref.def_id))
+                            }
+                        };
+
+                        let note_str = format!("candidate #{} is defined in an impl{} \
+                                                for the type `{}`",
+                                               idx + 1,
+                                               insertion,
+                                               impl_ty);
+                        if let Some(note_span) = note_span {
+                            // We have a span pointing to the method. Show note with snippet.
+                            err.span_note(note_span, &note_str);
+                        } else {
+                            err.note(&note_str);
+                        }
+                    }
+                    CandidateSource::TraitSource(trait_did) => {
+                        let item = self.trait_item(trait_did, item_name).unwrap();
+                        let item_span = self.tcx.map.def_id_span(item.def_id(), span);
+                        span_note!(err, item_span,
+                                   "candidate #{} is defined in the trait `{}`",
+                                   idx + 1,
+                                   self.tcx.item_path_str(trait_did));
+                    }
+                }
+            }
+        };
+
+        match error {
+            MethodError::NoMatch(NoMatchData { static_candidates: static_sources,
+                                               unsatisfied_predicates,
+                                               out_of_scope_traits,
+                                               mode, .. }) => {
+                let tcx = self.tcx;
+
+                let mut err = self.type_error_struct(
+                    span,
+                    |actual| {
+                        format!("no {} named `{}` found for type `{}` \
+                                 in the current scope",
+                                if mode == Mode::MethodCall { "method" }
+                                else { "associated item" },
+                                item_name,
+                                actual)
+                    },
+                    rcvr_ty,
+                    None);
+
+                // If the item has the name of a field, give a help note
+                if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) {
+                    if let Some(field) = def.struct_variant().find_field_named(item_name) {
+                        let expr_string = match tcx.sess.codemap().span_to_snippet(expr.span) {
+                            Ok(expr_string) => expr_string,
+                            _ => "s".into() // Default to a generic placeholder for the
+                                            // expression when we can't generate a string
+                                            // snippet
+                        };
+
+                        let field_ty = field.ty(tcx, substs);
+
+                        if self.is_fn_ty(&field_ty, span) {
+                            err.span_note(span,
+                                          &format!("use `({0}.{1})(...)` if you meant to call \
+                                                   the function stored in the `{1}` field",
+                                                   expr_string, item_name));
+                        } else {
+                            err.span_note(span, &format!("did you mean to write `{0}.{1}`?",
+                                                         expr_string, item_name));
+                        }
+                    }
+                }
+
+                if self.is_fn_ty(&rcvr_ty, span) {
+                    macro_rules! report_function {
+                        ($span:expr, $name:expr) => {
+                            err.note(&format!("{} is a function, perhaps you wish to call it",
+                                         $name));
+                        }
+                    }
+
+                    if let Some(expr) = rcvr_expr {
+                        if let Ok (expr_string) = tcx.sess.codemap().span_to_snippet(expr.span) {
+                            report_function!(expr.span, expr_string);
+                        }
+                        else if let Expr_::ExprPath(_, path) = expr.node.clone() {
+                            if let Some(segment) = path.segments.last() {
+                                report_function!(expr.span, segment.identifier.name);
+                            }
+                        }
+                    }
+                }
+
+                if !static_sources.is_empty() {
+                    err.note(
+                        "found the following associated functions; to be used as \
+                         methods, functions must have a `self` parameter");
+
+                    report_candidates(&mut err, static_sources);
+                }
+
+                if !unsatisfied_predicates.is_empty() {
+                    let bound_list = unsatisfied_predicates.iter()
+                        .map(|p| format!("`{} : {}`",
+                                         p.self_ty(),
+                                         p))
+                        .collect::<Vec<_>>()
+                        .join(", ");
+                    err.note(
+                        &format!("the method `{}` exists but the \
+                                 following trait bounds were not satisfied: {}",
+                                 item_name,
+                                 bound_list));
+                }
+
+                self.suggest_traits_to_import(&mut err, span, rcvr_ty, item_name,
+                                              rcvr_expr, out_of_scope_traits);
+                err.emit();
+            }
+
+            MethodError::Ambiguity(sources) => {
+                let mut err = struct_span_err!(self.sess(), span, E0034,
+                                               "multiple applicable items in scope");
+
+                report_candidates(&mut err, sources);
+                err.emit();
+            }
+
+            MethodError::ClosureAmbiguity(trait_def_id) => {
+                let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \
+                                   invoked on this closure as we have not yet inferred what \
+                                   kind of closure it is",
+                                   item_name,
+                                   self.tcx.item_path_str(trait_def_id));
+                let msg = if let Some(callee) = rcvr_expr {
+                    format!("{}; use overloaded call notation instead (e.g., `{}()`)",
+                            msg, pprust::expr_to_string(callee))
+                } else {
+                    msg
+                };
+                self.sess().span_err(span, &msg);
+            }
+
+            MethodError::PrivateMatch(def) => {
+                let msg = format!("{} `{}` is private", def.kind_name(), item_name);
+                self.tcx.sess.span_err(span, &msg);
+            }
+        }
+    }
+
+    fn suggest_traits_to_import(&self,
+                                err: &mut DiagnosticBuilder,
+                                span: Span,
+                                rcvr_ty: Ty<'tcx>,
+                                item_name: ast::Name,
+                                rcvr_expr: Option<&hir::Expr>,
+                                valid_out_of_scope_traits: Vec<DefId>)
+    {
+        if !valid_out_of_scope_traits.is_empty() {
+            let mut candidates = valid_out_of_scope_traits;
+            candidates.sort();
+            candidates.dedup();
+            let msg = format!(
+                "items from traits can only be used if the trait is in scope; \
+                 the following {traits_are} implemented but not in scope, \
+                 perhaps add a `use` for {one_of_them}:",
+                traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"},
+                one_of_them = if candidates.len() == 1 {"it"} else {"one of them"});
+
+            err.help(&msg[..]);
+
+            for (i, trait_did) in candidates.iter().enumerate() {
+                err.help(&format!("candidate #{}: `use {}`",
+                                  i + 1,
+                                  self.tcx.item_path_str(*trait_did)));
+            }
+            return
+        }
+
+        let type_is_local = self.type_derefs_to_local(span, rcvr_ty, rcvr_expr);
+
+        // there's no implemented traits, so lets suggest some traits to
+        // implement, by finding ones that have the item name, and are
+        // legal to implement.
+        let mut candidates = all_traits(self.ccx)
+            .filter(|info| {
+                // we approximate the coherence rules to only suggest
+                // traits that are legal to implement by requiring that
+                // either the type or trait is local. Multidispatch means
+                // this isn't perfect (that is, there are cases when
+                // implementing a trait would be legal but is rejected
+                // here).
+                (type_is_local || info.def_id.is_local())
+                    && self.trait_item(info.def_id, item_name).is_some()
+            })
+            .collect::<Vec<_>>();
+
+        if !candidates.is_empty() {
+            // sort from most relevant to least relevant
+            candidates.sort_by(|a, b| a.cmp(b).reverse());
+            candidates.dedup();
+
+            // FIXME #21673 this help message could be tuned to the case
+            // of a type parameter: suggest adding a trait bound rather
+            // than implementing.
+            let msg = format!(
+                "items from traits can only be used if the trait is implemented and in scope; \
+                 the following {traits_define} an item `{name}`, \
+                 perhaps you need to implement {one_of_them}:",
+                traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"},
+                one_of_them = if candidates.len() == 1 {"it"} else {"one of them"},
+                name = item_name);
+
+            err.help(&msg[..]);
+
+            for (i, trait_info) in candidates.iter().enumerate() {
+                err.help(&format!("candidate #{}: `{}`",
+                                  i + 1,
+                                  self.tcx.item_path_str(trait_info.def_id)));
+            }
+        }
+    }
+
+    /// Checks whether there is a local type somewhere in the chain of
+    /// autoderefs of `rcvr_ty`.
+    fn type_derefs_to_local(&self,
                             span: Span,
                             rcvr_ty: Ty<'tcx>,
-                            item_name: ast::Name,
-                            rcvr_expr: Option<&hir::Expr>,
-                            valid_out_of_scope_traits: Vec<DefId>)
-{
-    if !valid_out_of_scope_traits.is_empty() {
-        let mut candidates = valid_out_of_scope_traits;
-        candidates.sort();
-        candidates.dedup();
-        let msg = format!(
-            "items from traits can only be used if the trait is in scope; \
-             the following {traits_are} implemented but not in scope, \
-             perhaps add a `use` for {one_of_them}:",
-            traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"},
-            one_of_them = if candidates.len() == 1 {"it"} else {"one of them"});
+                            rcvr_expr: Option<&hir::Expr>) -> bool {
+        fn is_local(ty: Ty) -> bool {
+            match ty.sty {
+                ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(),
 
-        err.help(&msg[..]);
+                ty::TyTrait(ref tr) => tr.principal_def_id().is_local(),
 
-        for (i, trait_did) in candidates.iter().enumerate() {
-            err.help(&format!("candidate #{}: `use {}`",
-                              i + 1,
-                              self.tcx.item_path_str(*trait_did)));
+                ty::TyParam(_) => true,
+
+                // everything else (primitive types etc.) is effectively
+                // non-local (there are "edge" cases, e.g. (LocalType,), but
+                // the noise from these sort of types is usually just really
+                // annoying, rather than any sort of help).
+                _ => false
+            }
         }
-        return
-    }
 
-    let type_is_local = self.type_derefs_to_local(span, rcvr_ty, rcvr_expr);
-
-    // there's no implemented traits, so lets suggest some traits to
-    // implement, by finding ones that have the item name, and are
-    // legal to implement.
-    let mut candidates = all_traits(self.ccx)
-        .filter(|info| {
-            // we approximate the coherence rules to only suggest
-            // traits that are legal to implement by requiring that
-            // either the type or trait is local. Multidispatch means
-            // this isn't perfect (that is, there are cases when
-            // implementing a trait would be legal but is rejected
-            // here).
-            (type_is_local || info.def_id.is_local())
-                && self.trait_item(info.def_id, item_name).is_some()
-        })
-        .collect::<Vec<_>>();
-
-    if !candidates.is_empty() {
-        // sort from most relevant to least relevant
-        candidates.sort_by(|a, b| a.cmp(b).reverse());
-        candidates.dedup();
-
-        // FIXME #21673 this help message could be tuned to the case
-        // of a type parameter: suggest adding a trait bound rather
-        // than implementing.
-        let msg = format!(
-            "items from traits can only be used if the trait is implemented and in scope; \
-             the following {traits_define} an item `{name}`, \
-             perhaps you need to implement {one_of_them}:",
-            traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"},
-            one_of_them = if candidates.len() == 1 {"it"} else {"one of them"},
-            name = item_name);
-
-        err.help(&msg[..]);
-
-        for (i, trait_info) in candidates.iter().enumerate() {
-            err.help(&format!("candidate #{}: `{}`",
-                              i + 1,
-                              self.tcx.item_path_str(trait_info.def_id)));
+        // This occurs for UFCS desugaring of `T::method`, where there is no
+        // receiver expression for the method call, and thus no autoderef.
+        if rcvr_expr.is_none() {
+            return is_local(self.resolve_type_vars_with_obligations(rcvr_ty));
         }
+
+        self.autoderef(span, rcvr_ty, || None,
+                       check::UnresolvedTypeAction::Ignore, ty::NoPreference,
+                       |ty, _| {
+            if is_local(ty) {
+                Some(())
+            } else {
+                None
+            }
+        }).2.is_some()
     }
 }
 
-/// Checks whether there is a local type somewhere in the chain of
-/// autoderefs of `rcvr_ty`.
-fn type_derefs_to_local(&self,
-                        span: Span,
-                        rcvr_ty: Ty<'tcx>,
-                        rcvr_expr: Option<&hir::Expr>) -> bool {
-    fn is_local(ty: Ty) -> bool {
-        match ty.sty {
-            ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(),
-
-            ty::TyTrait(ref tr) => tr.principal_def_id().is_local(),
-
-            ty::TyParam(_) => true,
-
-            // everything else (primitive types etc.) is effectively
-            // non-local (there are "edge" cases, e.g. (LocalType,), but
-            // the noise from these sort of types is usually just really
-            // annoying, rather than any sort of help).
-            _ => false
-        }
-    }
-
-    // This occurs for UFCS desugaring of `T::method`, where there is no
-    // receiver expression for the method call, and thus no autoderef.
-    if rcvr_expr.is_none() {
-        return is_local(self.resolve_type_vars_with_obligations(rcvr_ty));
-    }
-
-    self.autoderef(span, rcvr_ty, || None,
-                   check::UnresolvedTypeAction::Ignore, ty::NoPreference,
-                   |ty, _| {
-        if is_local(ty) {
-            Some(())
-        } else {
-            None
-        }
-    }).2.is_some()
-}
-}
-
 pub type AllTraitsVec = Vec<TraitInfo>;
 
 #[derive(Copy, Clone)]
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index ad0ccdcf389..f428023da9b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2015,7 +2015,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if let Some(_default) = default_map.get(ty) {
                     let resolved = self.resolve_type_vars_if_possible(ty);
 
-                    debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}",
+                    debug!("select_all_obligations_and_apply_defaults: \
+                            ty: {:?} with default: {:?}",
                              ty, _default);
 
                     match resolved.sty {
@@ -2209,676 +2210,679 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-/// Executes an autoderef loop for the type `t`. At each step, invokes `should_stop` to decide
-/// whether to terminate the loop. Returns the final type and number of derefs that it performed.
-///
-/// Note: this method does not modify the adjustments table. The caller is responsible for
-/// inserting an AutoAdjustment record into the `self` using one of the suitable methods.
-pub fn autoderef<'b, E, I, T, F>(&self,
-                                 sp: Span,
-                                 base_ty: Ty<'tcx>,
-                                 maybe_exprs: E,
-                                 unresolved_type_action: UnresolvedTypeAction,
-                                 mut lvalue_pref: LvaluePreference,
-                                 mut should_stop: F)
-                                 -> (Ty<'tcx>, usize, Option<T>)
-    // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
-    where E: Fn() -> I,
-          I: IntoIterator<Item=&'b hir::Expr>,
-          F: FnMut(Ty<'tcx>, usize) -> Option<T>,
-{
-    debug!("autoderef(base_ty={:?}, lvalue_pref={:?})",
-           base_ty, lvalue_pref);
+    /// Executes an autoderef loop for the type `t`. At each step, invokes `should_stop`
+    /// to decide whether to terminate the loop. Returns the final type and number of
+    /// derefs that it performed.
+    ///
+    /// Note: this method does not modify the adjustments table. The caller is responsible for
+    /// inserting an AutoAdjustment record into the `self` using one of the suitable methods.
+    pub fn autoderef<'b, E, I, T, F>(&self,
+                                     sp: Span,
+                                     base_ty: Ty<'tcx>,
+                                     maybe_exprs: E,
+                                     unresolved_type_action: UnresolvedTypeAction,
+                                     mut lvalue_pref: LvaluePreference,
+                                     mut should_stop: F)
+                                     -> (Ty<'tcx>, usize, Option<T>)
+        // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
+        where E: Fn() -> I,
+              I: IntoIterator<Item=&'b hir::Expr>,
+              F: FnMut(Ty<'tcx>, usize) -> Option<T>,
+    {
+        debug!("autoderef(base_ty={:?}, lvalue_pref={:?})",
+               base_ty, lvalue_pref);
 
-    let mut t = base_ty;
-    for autoderefs in 0..self.tcx.sess.recursion_limit.get() {
-        let resolved_t = match unresolved_type_action {
-            UnresolvedTypeAction::Error => {
-                self.structurally_resolved_type(sp, t)
+        let mut t = base_ty;
+        for autoderefs in 0..self.tcx.sess.recursion_limit.get() {
+            let resolved_t = match unresolved_type_action {
+                UnresolvedTypeAction::Error => {
+                    self.structurally_resolved_type(sp, t)
+                }
+                UnresolvedTypeAction::Ignore => {
+                    // We can continue even when the type cannot be resolved
+                    // (i.e. it is an inference variable) because `Ty::builtin_deref`
+                    // and `try_overloaded_deref` both simply return `None`
+                    // in such a case without producing spurious errors.
+                    self.resolve_type_vars_if_possible(&t)
+                }
+            };
+            if resolved_t.references_error() {
+                return (resolved_t, autoderefs, None);
             }
-            UnresolvedTypeAction::Ignore => {
-                // We can continue even when the type cannot be resolved
-                // (i.e. it is an inference variable) because `Ty::builtin_deref`
-                // and `try_overloaded_deref` both simply return `None`
-                // in such a case without producing spurious errors.
-                self.resolve_type_vars_if_possible(&t)
+
+            match should_stop(resolved_t, autoderefs) {
+                Some(x) => return (resolved_t, autoderefs, Some(x)),
+                None => {}
             }
+
+            // Otherwise, deref if type is derefable:
+
+            // Super subtle: it might seem as though we should
+            // pass `opt_expr` to `try_overloaded_deref`, so that
+            // the (implicit) autoref of using an overloaded deref
+            // would get added to the adjustment table. However we
+            // do not do that, because it's kind of a
+            // "meta-adjustment" -- instead, we just leave it
+            // unrecorded and know that there "will be" an
+            // autoref. regionck and other bits of the code base,
+            // when they encounter an overloaded autoderef, have
+            // to do some reconstructive surgery. This is a pretty
+            // complex mess that is begging for a proper MIR.
+            let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) {
+                mt
+            } else if let Some(method) = self.try_overloaded_deref(sp, None,
+                                                                   resolved_t, lvalue_pref) {
+                for expr in maybe_exprs() {
+                    let method_call = MethodCall::autoderef(expr.id, autoderefs as u32);
+                    self.tables.borrow_mut().method_map.insert(method_call, method);
+                }
+                self.make_overloaded_lvalue_return_type(method)
+            } else {
+                return (resolved_t, autoderefs, None);
+            };
+
+            t = mt.ty;
+            if mt.mutbl == hir::MutImmutable {
+                lvalue_pref = NoPreference;
+            }
+        }
+
+        // We've reached the recursion limit, error gracefully.
+        span_err!(self.tcx.sess, sp, E0055,
+            "reached the recursion limit while auto-dereferencing {:?}",
+            base_ty);
+        (self.tcx.types.err, 0, None)
+    }
+
+    fn try_overloaded_deref(&self,
+                            span: Span,
+                            base_expr: Option<&hir::Expr>,
+                            base_ty: Ty<'tcx>,
+                            lvalue_pref: LvaluePreference)
+                            -> Option<MethodCallee<'tcx>>
+    {
+        // Try DerefMut first, if preferred.
+        let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) {
+            (PreferMutLvalue, Some(trait_did)) => {
+                self.lookup_method_in_trait(span, base_expr,
+                                            token::intern("deref_mut"), trait_did,
+                                            base_ty, None)
+            }
+            _ => None
         };
-        if resolved_t.references_error() {
-            return (resolved_t, autoderefs, None);
-        }
 
-        match should_stop(resolved_t, autoderefs) {
-            Some(x) => return (resolved_t, autoderefs, Some(x)),
-            None => {}
-        }
-
-        // Otherwise, deref if type is derefable:
-
-        // Super subtle: it might seem as though we should
-        // pass `opt_expr` to `try_overloaded_deref`, so that
-        // the (implicit) autoref of using an overloaded deref
-        // would get added to the adjustment table. However we
-        // do not do that, because it's kind of a
-        // "meta-adjustment" -- instead, we just leave it
-        // unrecorded and know that there "will be" an
-        // autoref. regionck and other bits of the code base,
-        // when they encounter an overloaded autoderef, have
-        // to do some reconstructive surgery. This is a pretty
-        // complex mess that is begging for a proper MIR.
-        let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) {
-            mt
-        } else if let Some(method) = self.try_overloaded_deref(sp, None,
-                                                               resolved_t, lvalue_pref) {
-            for expr in maybe_exprs() {
-                let method_call = MethodCall::autoderef(expr.id, autoderefs as u32);
-                self.tables.borrow_mut().method_map.insert(method_call, method);
+        // Otherwise, fall back to Deref.
+        let method = match (method, self.tcx.lang_items.deref_trait()) {
+            (None, Some(trait_did)) => {
+                self.lookup_method_in_trait(span, base_expr,
+                                            token::intern("deref"), trait_did,
+                                            base_ty, None)
             }
-            self.make_overloaded_lvalue_return_type(method)
+            (method, _) => method
+        };
+
+        method
+    }
+
+    /// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait
+    /// returns a type of `&T`, but the actual type we assign to the
+    /// *expression* is `T`. So this function just peels off the return
+    /// type by one layer to yield `T`.
+    fn make_overloaded_lvalue_return_type(&self,
+                                          method: MethodCallee<'tcx>)
+                                          -> ty::TypeAndMut<'tcx>
+    {
+        // extract method return type, which will be &T;
+        // all LB regions should have been instantiated during method lookup
+        let ret_ty = method.ty.fn_ret();
+        let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap();
+
+        // method returns &T, but the type as visible to user is T, so deref
+        ret_ty.builtin_deref(true, NoPreference).unwrap()
+    }
+
+    fn lookup_indexing(&self,
+                       expr: &hir::Expr,
+                       base_expr: &'gcx hir::Expr,
+                       base_ty: Ty<'tcx>,
+                       idx_ty: Ty<'tcx>,
+                       lvalue_pref: LvaluePreference)
+                       -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
+    {
+        // FIXME(#18741) -- this is almost but not quite the same as the
+        // autoderef that normal method probing does. They could likely be
+        // consolidated.
+
+        let (ty, autoderefs, final_mt) = self.autoderef(base_expr.span,
+                                                        base_ty,
+                                                        || Some(base_expr),
+                                                        UnresolvedTypeAction::Error,
+                                                        lvalue_pref,
+                                                        |adj_ty, idx| {
+            self.try_index_step(MethodCall::expr(expr.id), expr, base_expr,
+                                adj_ty, idx, false, lvalue_pref, idx_ty)
+        });
+
+        if final_mt.is_some() {
+            return final_mt;
+        }
+
+        // After we have fully autoderef'd, if the resulting type is [T; n], then
+        // do a final unsized coercion to yield [T].
+        if let ty::TyArray(element_ty, _) = ty.sty {
+            let adjusted_ty = self.tcx.mk_slice(element_ty);
+            self.try_index_step(MethodCall::expr(expr.id), expr, base_expr,
+                                adjusted_ty, autoderefs, true, lvalue_pref, idx_ty)
         } else {
-            return (resolved_t, autoderefs, None);
+            None
+        }
+    }
+
+    /// To type-check `base_expr[index_expr]`, we progressively autoderef
+    /// (and otherwise adjust) `base_expr`, looking for a type which either
+    /// supports builtin indexing or overloaded indexing.
+    /// This loop implements one step in that search; the autoderef loop
+    /// is implemented by `lookup_indexing`.
+    fn try_index_step(&self,
+                      method_call: MethodCall,
+                      expr: &hir::Expr,
+                      base_expr: &'gcx hir::Expr,
+                      adjusted_ty: Ty<'tcx>,
+                      autoderefs: usize,
+                      unsize: bool,
+                      lvalue_pref: LvaluePreference,
+                      index_ty: Ty<'tcx>)
+                      -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
+    {
+        let tcx = self.tcx;
+        debug!("try_index_step(expr={:?}, base_expr.id={:?}, adjusted_ty={:?}, \
+                               autoderefs={}, unsize={}, index_ty={:?})",
+               expr,
+               base_expr,
+               adjusted_ty,
+               autoderefs,
+               unsize,
+               index_ty);
+
+        let input_ty = self.next_ty_var();
+
+        // First, try built-in indexing.
+        match (adjusted_ty.builtin_index(), &index_ty.sty) {
+            (Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
+                debug!("try_index_step: success, using built-in indexing");
+                // If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
+                assert!(!unsize);
+                self.write_autoderef_adjustment(base_expr.id, autoderefs);
+                return Some((tcx.types.usize, ty));
+            }
+            _ => {}
+        }
+
+        // Try `IndexMut` first, if preferred.
+        let method = match (lvalue_pref, tcx.lang_items.index_mut_trait()) {
+            (PreferMutLvalue, Some(trait_did)) => {
+                self.lookup_method_in_trait_adjusted(expr.span,
+                                                     Some(&base_expr),
+                                                     token::intern("index_mut"),
+                                                     trait_did,
+                                                     autoderefs,
+                                                     unsize,
+                                                     adjusted_ty,
+                                                     Some(vec![input_ty]))
+            }
+            _ => None,
         };
 
-        t = mt.ty;
-        if mt.mutbl == hir::MutImmutable {
-            lvalue_pref = NoPreference;
-        }
-    }
-
-    // We've reached the recursion limit, error gracefully.
-    span_err!(self.tcx.sess, sp, E0055,
-        "reached the recursion limit while auto-dereferencing {:?}",
-        base_ty);
-    (self.tcx.types.err, 0, None)
-}
-
-fn try_overloaded_deref(&self,
-                        span: Span,
-                        base_expr: Option<&hir::Expr>,
-                        base_ty: Ty<'tcx>,
-                        lvalue_pref: LvaluePreference)
-                        -> Option<MethodCallee<'tcx>>
-{
-    // Try DerefMut first, if preferred.
-    let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) {
-        (PreferMutLvalue, Some(trait_did)) => {
-            self.lookup_method_in_trait(span, base_expr,
-                                        token::intern("deref_mut"), trait_did,
-                                        base_ty, None)
-        }
-        _ => None
-    };
-
-    // Otherwise, fall back to Deref.
-    let method = match (method, self.tcx.lang_items.deref_trait()) {
-        (None, Some(trait_did)) => {
-            self.lookup_method_in_trait(span, base_expr,
-                                        token::intern("deref"), trait_did,
-                                        base_ty, None)
-        }
-        (method, _) => method
-    };
-
-    method
-}
-
-/// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait returns a type of `&T`, but the
-/// actual type we assign to the *expression* is `T`. So this function just peels off the return
-/// type by one layer to yield `T`.
-fn make_overloaded_lvalue_return_type(&self,
-                                      method: MethodCallee<'tcx>)
-                                      -> ty::TypeAndMut<'tcx>
-{
-    // extract method return type, which will be &T;
-    // all LB regions should have been instantiated during method lookup
-    let ret_ty = method.ty.fn_ret();
-    let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap();
-
-    // method returns &T, but the type as visible to user is T, so deref
-    ret_ty.builtin_deref(true, NoPreference).unwrap()
-}
-
-fn lookup_indexing(&self,
-                   expr: &hir::Expr,
-                   base_expr: &'gcx hir::Expr,
-                   base_ty: Ty<'tcx>,
-                   idx_ty: Ty<'tcx>,
-                   lvalue_pref: LvaluePreference)
-                   -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
-{
-    // FIXME(#18741) -- this is almost but not quite the same as the
-    // autoderef that normal method probing does. They could likely be
-    // consolidated.
-
-    let (ty, autoderefs, final_mt) = self.autoderef(base_expr.span,
-                                                    base_ty,
-                                                    || Some(base_expr),
-                                                    UnresolvedTypeAction::Error,
-                                                    lvalue_pref,
-                                                    |adj_ty, idx| {
-        self.try_index_step(MethodCall::expr(expr.id), expr, base_expr,
-                            adj_ty, idx, false, lvalue_pref, idx_ty)
-    });
-
-    if final_mt.is_some() {
-        return final_mt;
-    }
-
-    // After we have fully autoderef'd, if the resulting type is [T; n], then
-    // do a final unsized coercion to yield [T].
-    if let ty::TyArray(element_ty, _) = ty.sty {
-        let adjusted_ty = self.tcx.mk_slice(element_ty);
-        self.try_index_step(MethodCall::expr(expr.id), expr, base_expr,
-                            adjusted_ty, autoderefs, true, lvalue_pref, idx_ty)
-    } else {
-        None
-    }
-}
-
-/// To type-check `base_expr[index_expr]`, we progressively autoderef (and otherwise adjust)
-/// `base_expr`, looking for a type which either supports builtin indexing or overloaded indexing.
-/// This loop implements one step in that search; the autoderef loop is implemented by
-/// `lookup_indexing`.
-fn try_index_step(&self,
-                  method_call: MethodCall,
-                  expr: &hir::Expr,
-                  base_expr: &'gcx hir::Expr,
-                  adjusted_ty: Ty<'tcx>,
-                  autoderefs: usize,
-                  unsize: bool,
-                  lvalue_pref: LvaluePreference,
-                  index_ty: Ty<'tcx>)
-                  -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
-{
-    let tcx = self.tcx;
-    debug!("try_index_step(expr={:?}, base_expr.id={:?}, adjusted_ty={:?}, \
-                           autoderefs={}, unsize={}, index_ty={:?})",
-           expr,
-           base_expr,
-           adjusted_ty,
-           autoderefs,
-           unsize,
-           index_ty);
-
-    let input_ty = self.next_ty_var();
-
-    // First, try built-in indexing.
-    match (adjusted_ty.builtin_index(), &index_ty.sty) {
-        (Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
-            debug!("try_index_step: success, using built-in indexing");
-            // If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
-            assert!(!unsize);
-            self.write_autoderef_adjustment(base_expr.id, autoderefs);
-            return Some((tcx.types.usize, ty));
-        }
-        _ => {}
-    }
-
-    // Try `IndexMut` first, if preferred.
-    let method = match (lvalue_pref, tcx.lang_items.index_mut_trait()) {
-        (PreferMutLvalue, Some(trait_did)) => {
-            self.lookup_method_in_trait_adjusted(expr.span,
-                                                 Some(&base_expr),
-                                                 token::intern("index_mut"),
-                                                 trait_did,
-                                                 autoderefs,
-                                                 unsize,
-                                                 adjusted_ty,
-                                                 Some(vec![input_ty]))
-        }
-        _ => None,
-    };
-
-    // Otherwise, fall back to `Index`.
-    let method = match (method, tcx.lang_items.index_trait()) {
-        (None, Some(trait_did)) => {
-            self.lookup_method_in_trait_adjusted(expr.span,
-                                                 Some(&base_expr),
-                                                 token::intern("index"),
-                                                 trait_did,
-                                                 autoderefs,
-                                                 unsize,
-                                                 adjusted_ty,
-                                                 Some(vec![input_ty]))
-        }
-        (method, _) => method,
-    };
-
-    // If some lookup succeeds, write callee into table and extract index/element
-    // type from the method signature.
-    // If some lookup succeeded, install method in table
-    method.map(|method| {
-        debug!("try_index_step: success, using overloaded indexing");
-        self.tables.borrow_mut().method_map.insert(method_call, method);
-        (input_ty, self.make_overloaded_lvalue_return_type(method).ty)
-    })
-}
-
-fn check_method_argument_types(&self,
-                               sp: Span,
-                               method_fn_ty: Ty<'tcx>,
-                               callee_expr: &'gcx hir::Expr,
-                               args_no_rcvr: &'gcx [P<hir::Expr>],
-                               tuple_arguments: TupleArgumentsFlag,
-                               expected: Expectation<'tcx>)
-                               -> ty::FnOutput<'tcx> {
-    if method_fn_ty.references_error() {
-        let err_inputs = self.err_args(args_no_rcvr.len());
-
-        let err_inputs = match tuple_arguments {
-            DontTupleArguments => err_inputs,
-            TupleArguments => vec![self.tcx.mk_tup(err_inputs)],
+        // Otherwise, fall back to `Index`.
+        let method = match (method, tcx.lang_items.index_trait()) {
+            (None, Some(trait_did)) => {
+                self.lookup_method_in_trait_adjusted(expr.span,
+                                                     Some(&base_expr),
+                                                     token::intern("index"),
+                                                     trait_did,
+                                                     autoderefs,
+                                                     unsize,
+                                                     adjusted_ty,
+                                                     Some(vec![input_ty]))
+            }
+            (method, _) => method,
         };
 
-        self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
-                                  false, tuple_arguments);
-        ty::FnConverging(self.tcx.types.err)
-    } else {
-        match method_fn_ty.sty {
-            ty::TyFnDef(_, _, ref fty) => {
-                // HACK(eddyb) ignore self in the definition (see above).
-                let expected_arg_tys = self.expected_types_for_fn_args(sp, expected,
-                                                                       fty.sig.0.output,
-                                                                       &fty.sig.0.inputs[1..]);
-                self.check_argument_types(sp, &fty.sig.0.inputs[1..], &expected_arg_tys[..],
-                                          args_no_rcvr, fty.sig.0.variadic, tuple_arguments);
-                fty.sig.0.output
-            }
-            _ => {
-                span_bug!(callee_expr.span, "method without bare fn type");
-            }
-        }
-    }
-}
-
-/// Generic function that factors out common logic from function calls, method calls and overloaded
-/// operators.
-fn check_argument_types(&self,
-                        sp: Span,
-                        fn_inputs: &[Ty<'tcx>],
-                        expected_arg_tys: &[Ty<'tcx>],
-                        args: &'gcx [P<hir::Expr>],
-                        variadic: bool,
-                        tuple_arguments: TupleArgumentsFlag) {
-    let tcx = self.tcx;
-
-    // Grab the argument types, supplying fresh type variables
-    // if the wrong number of arguments were supplied
-    let supplied_arg_count = if tuple_arguments == DontTupleArguments {
-        args.len()
-    } else {
-        1
-    };
-
-    // All the input types from the fn signature must outlive the call
-    // so as to validate implied bounds.
-    for &fn_input_ty in fn_inputs {
-        self.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation);
+        // If some lookup succeeds, write callee into table and extract index/element
+        // type from the method signature.
+        // If some lookup succeeded, install method in table
+        method.map(|method| {
+            debug!("try_index_step: success, using overloaded indexing");
+            self.tables.borrow_mut().method_map.insert(method_call, method);
+            (input_ty, self.make_overloaded_lvalue_return_type(method).ty)
+        })
     }
 
-    let mut expected_arg_tys = expected_arg_tys;
-    let expected_arg_count = fn_inputs.len();
-    let formal_tys = if tuple_arguments == TupleArguments {
-        let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
-        match tuple_type.sty {
-            ty::TyTuple(arg_types) => {
-                if arg_types.len() != args.len() {
-                    span_err!(tcx.sess, sp, E0057,
-                        "this function takes {} parameter{} but {} parameter{} supplied",
-                        arg_types.len(),
-                        if arg_types.len() == 1 {""} else {"s"},
-                        args.len(),
-                        if args.len() == 1 {" was"} else {"s were"});
-                    expected_arg_tys = &[];
-                    self.err_args(args.len())
-                } else {
-                    expected_arg_tys = match expected_arg_tys.get(0) {
-                        Some(&ty) => match ty.sty {
-                            ty::TyTuple(ref tys) => &tys,
-                            _ => &[]
-                        },
-                        None => &[]
-                    };
-                    arg_types.to_vec()
+    fn check_method_argument_types(&self,
+                                   sp: Span,
+                                   method_fn_ty: Ty<'tcx>,
+                                   callee_expr: &'gcx hir::Expr,
+                                   args_no_rcvr: &'gcx [P<hir::Expr>],
+                                   tuple_arguments: TupleArgumentsFlag,
+                                   expected: Expectation<'tcx>)
+                                   -> ty::FnOutput<'tcx> {
+        if method_fn_ty.references_error() {
+            let err_inputs = self.err_args(args_no_rcvr.len());
+
+            let err_inputs = match tuple_arguments {
+                DontTupleArguments => err_inputs,
+                TupleArguments => vec![self.tcx.mk_tup(err_inputs)],
+            };
+
+            self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
+                                      false, tuple_arguments);
+            ty::FnConverging(self.tcx.types.err)
+        } else {
+            match method_fn_ty.sty {
+                ty::TyFnDef(_, _, ref fty) => {
+                    // HACK(eddyb) ignore self in the definition (see above).
+                    let expected_arg_tys = self.expected_types_for_fn_args(sp, expected,
+                                                                           fty.sig.0.output,
+                                                                           &fty.sig.0.inputs[1..]);
+                    self.check_argument_types(sp, &fty.sig.0.inputs[1..], &expected_arg_tys[..],
+                                              args_no_rcvr, fty.sig.0.variadic, tuple_arguments);
+                    fty.sig.0.output
+                }
+                _ => {
+                    span_bug!(callee_expr.span, "method without bare fn type");
                 }
             }
-            _ => {
-                span_err!(tcx.sess, sp, E0059,
-                    "cannot use call notation; the first type parameter \
-                     for the function trait is neither a tuple nor unit");
-                expected_arg_tys = &[];
-                self.err_args(args.len())
-            }
         }
-    } else if expected_arg_count == supplied_arg_count {
-        fn_inputs.to_vec()
-    } else if variadic {
-        if supplied_arg_count >= expected_arg_count {
-            fn_inputs.to_vec()
+    }
+
+    /// Generic function that factors out common logic from function calls,
+    /// method calls and overloaded operators.
+    fn check_argument_types(&self,
+                            sp: Span,
+                            fn_inputs: &[Ty<'tcx>],
+                            expected_arg_tys: &[Ty<'tcx>],
+                            args: &'gcx [P<hir::Expr>],
+                            variadic: bool,
+                            tuple_arguments: TupleArgumentsFlag) {
+        let tcx = self.tcx;
+
+        // Grab the argument types, supplying fresh type variables
+        // if the wrong number of arguments were supplied
+        let supplied_arg_count = if tuple_arguments == DontTupleArguments {
+            args.len()
         } else {
-            span_err!(tcx.sess, sp, E0060,
-                "this function takes at least {} parameter{} \
-                 but {} parameter{} supplied",
+            1
+        };
+
+        // All the input types from the fn signature must outlive the call
+        // so as to validate implied bounds.
+        for &fn_input_ty in fn_inputs {
+            self.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation);
+        }
+
+        let mut expected_arg_tys = expected_arg_tys;
+        let expected_arg_count = fn_inputs.len();
+        let formal_tys = if tuple_arguments == TupleArguments {
+            let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
+            match tuple_type.sty {
+                ty::TyTuple(arg_types) => {
+                    if arg_types.len() != args.len() {
+                        span_err!(tcx.sess, sp, E0057,
+                            "this function takes {} parameter{} but {} parameter{} supplied",
+                            arg_types.len(),
+                            if arg_types.len() == 1 {""} else {"s"},
+                            args.len(),
+                            if args.len() == 1 {" was"} else {"s were"});
+                        expected_arg_tys = &[];
+                        self.err_args(args.len())
+                    } else {
+                        expected_arg_tys = match expected_arg_tys.get(0) {
+                            Some(&ty) => match ty.sty {
+                                ty::TyTuple(ref tys) => &tys,
+                                _ => &[]
+                            },
+                            None => &[]
+                        };
+                        arg_types.to_vec()
+                    }
+                }
+                _ => {
+                    span_err!(tcx.sess, sp, E0059,
+                        "cannot use call notation; the first type parameter \
+                         for the function trait is neither a tuple nor unit");
+                    expected_arg_tys = &[];
+                    self.err_args(args.len())
+                }
+            }
+        } else if expected_arg_count == supplied_arg_count {
+            fn_inputs.to_vec()
+        } else if variadic {
+            if supplied_arg_count >= expected_arg_count {
+                fn_inputs.to_vec()
+            } else {
+                span_err!(tcx.sess, sp, E0060,
+                    "this function takes at least {} parameter{} \
+                     but {} parameter{} supplied",
+                    expected_arg_count,
+                    if expected_arg_count == 1 {""} else {"s"},
+                    supplied_arg_count,
+                    if supplied_arg_count == 1 {" was"} else {"s were"});
+                expected_arg_tys = &[];
+                self.err_args(supplied_arg_count)
+            }
+        } else {
+            span_err!(tcx.sess, sp, E0061,
+                "this function takes {} parameter{} but {} parameter{} supplied",
                 expected_arg_count,
                 if expected_arg_count == 1 {""} else {"s"},
                 supplied_arg_count,
                 if supplied_arg_count == 1 {" was"} else {"s were"});
             expected_arg_tys = &[];
             self.err_args(supplied_arg_count)
-        }
-    } else {
-        span_err!(tcx.sess, sp, E0061,
-            "this function takes {} parameter{} but {} parameter{} supplied",
-            expected_arg_count,
-            if expected_arg_count == 1 {""} else {"s"},
-            supplied_arg_count,
-            if supplied_arg_count == 1 {" was"} else {"s were"});
-        expected_arg_tys = &[];
-        self.err_args(supplied_arg_count)
-    };
-
-    debug!("check_argument_types: formal_tys={:?}",
-           formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>());
-
-    // Check the arguments.
-    // We do this in a pretty awful way: first we typecheck any arguments
-    // that are not anonymous functions, then we typecheck the anonymous
-    // functions. This is so that we have more information about the types
-    // of arguments when we typecheck the functions. This isn't really the
-    // right way to do this.
-    let xs = [false, true];
-    let mut any_diverges = false; // has any of the arguments diverged?
-    let mut warned = false; // have we already warned about unreachable code?
-    for check_blocks in &xs {
-        let check_blocks = *check_blocks;
-        debug!("check_blocks={}", check_blocks);
-
-        // More awful hacks: before we check argument types, try to do
-        // an "opportunistic" vtable resolution of any trait bounds on
-        // the call. This helps coercions.
-        if check_blocks {
-            self.select_obligations_where_possible();
-        }
-
-        // For variadic functions, we don't have a declared type for all of
-        // the arguments hence we only do our usual type checking with
-        // the arguments who's types we do know.
-        let t = if variadic {
-            expected_arg_count
-        } else if tuple_arguments == TupleArguments {
-            args.len()
-        } else {
-            supplied_arg_count
         };
-        for (i, arg) in args.iter().take(t).enumerate() {
+
+        debug!("check_argument_types: formal_tys={:?}",
+               formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>());
+
+        // Check the arguments.
+        // We do this in a pretty awful way: first we typecheck any arguments
+        // that are not anonymous functions, then we typecheck the anonymous
+        // functions. This is so that we have more information about the types
+        // of arguments when we typecheck the functions. This isn't really the
+        // right way to do this.
+        let xs = [false, true];
+        let mut any_diverges = false; // has any of the arguments diverged?
+        let mut warned = false; // have we already warned about unreachable code?
+        for check_blocks in &xs {
+            let check_blocks = *check_blocks;
+            debug!("check_blocks={}", check_blocks);
+
+            // More awful hacks: before we check argument types, try to do
+            // an "opportunistic" vtable resolution of any trait bounds on
+            // the call. This helps coercions.
+            if check_blocks {
+                self.select_obligations_where_possible();
+            }
+
+            // For variadic functions, we don't have a declared type for all of
+            // the arguments hence we only do our usual type checking with
+            // the arguments who's types we do know.
+            let t = if variadic {
+                expected_arg_count
+            } else if tuple_arguments == TupleArguments {
+                args.len()
+            } else {
+                supplied_arg_count
+            };
+            for (i, arg) in args.iter().take(t).enumerate() {
+                if any_diverges && !warned {
+                    self.tcx
+                        .sess
+                        .add_lint(lint::builtin::UNREACHABLE_CODE,
+                                  arg.id,
+                                  arg.span,
+                                  "unreachable expression".to_string());
+                    warned = true;
+                }
+                let is_block = match arg.node {
+                    hir::ExprClosure(..) => true,
+                    _ => false
+                };
+
+                if is_block == check_blocks {
+                    debug!("checking the argument");
+                    let formal_ty = formal_tys[i];
+
+                    // The special-cased logic below has three functions:
+                    // 1. Provide as good of an expected type as possible.
+                    let expected = expected_arg_tys.get(i).map(|&ty| {
+                        Expectation::rvalue_hint(self, ty)
+                    });
+
+                    self.check_expr_with_expectation(&arg,
+                        expected.unwrap_or(ExpectHasType(formal_ty)));
+                    // 2. Coerce to the most detailed type that could be coerced
+                    //    to, which is `expected_ty` if `rvalue_hint` returns an
+                    //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+                    let coerce_ty = expected.and_then(|e| e.only_has_type(self));
+                    self.demand_coerce(&arg, coerce_ty.unwrap_or(formal_ty));
+
+                    // 3. Relate the expected type and the formal one,
+                    //    if the expected type was used for the coercion.
+                    coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty));
+                }
+
+                if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) {
+                    any_diverges = any_diverges || self.type_var_diverges(arg_ty);
+                }
+            }
             if any_diverges && !warned {
+                let parent = self.tcx.map.get_parent_node(args[0].id);
                 self.tcx
                     .sess
                     .add_lint(lint::builtin::UNREACHABLE_CODE,
-                              arg.id,
-                              arg.span,
-                              "unreachable expression".to_string());
+                              parent,
+                              sp,
+                              "unreachable call".to_string());
                 warned = true;
             }
-            let is_block = match arg.node {
-                hir::ExprClosure(..) => true,
-                _ => false
-            };
 
-            if is_block == check_blocks {
-                debug!("checking the argument");
-                let formal_ty = formal_tys[i];
+        }
 
-                // The special-cased logic below has three functions:
-                // 1. Provide as good of an expected type as possible.
-                let expected = expected_arg_tys.get(i).map(|&ty| {
-                    Expectation::rvalue_hint(self, ty)
+        // We also need to make sure we at least write the ty of the other
+        // arguments which we skipped above.
+        if variadic {
+            for arg in args.iter().skip(expected_arg_count) {
+                self.check_expr(&arg);
+
+                // There are a few types which get autopromoted when passed via varargs
+                // in C but we just error out instead and require explicit casts.
+                let arg_ty = self.structurally_resolved_type(arg.span,
+                                                             self.expr_ty(&arg));
+                match arg_ty.sty {
+                    ty::TyFloat(ast::FloatTy::F32) => {
+                        self.type_error_message(arg.span, |t| {
+                            format!("can't pass an `{}` to variadic \
+                                     function, cast to `c_double`", t)
+                        }, arg_ty, None);
+                    }
+                    ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => {
+                        self.type_error_message(arg.span, |t| {
+                            format!("can't pass `{}` to variadic \
+                                     function, cast to `c_int`",
+                                           t)
+                        }, arg_ty, None);
+                    }
+                    ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => {
+                        self.type_error_message(arg.span, |t| {
+                            format!("can't pass `{}` to variadic \
+                                     function, cast to `c_uint`",
+                                           t)
+                        }, arg_ty, None);
+                    }
+                    ty::TyFnDef(_, _, f) => {
+                        let ptr_ty = self.tcx.mk_fn_ptr(f);
+                        let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty);
+                        self.type_error_message(arg.span,
+                                                |t| {
+                            format!("can't pass `{}` to variadic \
+                                     function, cast to `{}`", t, ptr_ty)
+                        }, arg_ty, None);
+                    }
+                    _ => {}
+                }
+            }
+        }
+    }
+
+    fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
+        (0..len).map(|_| self.tcx.types.err).collect()
+    }
+
+    fn write_call(&self,
+                  call_expr: &hir::Expr,
+                  output: ty::FnOutput<'tcx>) {
+        self.write_ty(call_expr.id, match output {
+            ty::FnConverging(output_ty) => output_ty,
+            ty::FnDiverging => self.next_diverging_ty_var()
+        });
+    }
+
+    // AST fragment checking
+    fn check_lit(&self,
+                 lit: &ast::Lit,
+                 expected: Expectation<'tcx>)
+                 -> Ty<'tcx>
+    {
+        let tcx = self.tcx;
+
+        match lit.node {
+            ast::LitKind::Str(..) => tcx.mk_static_str(),
+            ast::LitKind::ByteStr(ref v) => {
+                tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
+                                tcx.mk_array(tcx.types.u8, v.len()))
+            }
+            ast::LitKind::Byte(_) => tcx.types.u8,
+            ast::LitKind::Char(_) => tcx.types.char,
+            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
+            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
+            ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
+                let opt_ty = expected.to_option(self).and_then(|ty| {
+                    match ty.sty {
+                        ty::TyInt(_) | ty::TyUint(_) => Some(ty),
+                        ty::TyChar => Some(tcx.types.u8),
+                        ty::TyRawPtr(..) => Some(tcx.types.usize),
+                        ty::TyFnDef(..) | ty::TyFnPtr(_) => Some(tcx.types.usize),
+                        _ => None
+                    }
                 });
-
-                self.check_expr_with_expectation(&arg,
-                    expected.unwrap_or(ExpectHasType(formal_ty)));
-                // 2. Coerce to the most detailed type that could be coerced
-                //    to, which is `expected_ty` if `rvalue_hint` returns an
-                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
-                let coerce_ty = expected.and_then(|e| e.only_has_type(self));
-                self.demand_coerce(&arg, coerce_ty.unwrap_or(formal_ty));
-
-                // 3. Relate the expected type and the formal one,
-                //    if the expected type was used for the coercion.
-                coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty));
+                opt_ty.unwrap_or_else(
+                    || tcx.mk_int_var(self.next_int_var_id()))
             }
-
-            if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) {
-                any_diverges = any_diverges || self.type_var_diverges(arg_ty);
+            ast::LitKind::Float(_, t) => tcx.mk_mach_float(t),
+            ast::LitKind::FloatUnsuffixed(_) => {
+                let opt_ty = expected.to_option(self).and_then(|ty| {
+                    match ty.sty {
+                        ty::TyFloat(_) => Some(ty),
+                        _ => None
+                    }
+                });
+                opt_ty.unwrap_or_else(
+                    || tcx.mk_float_var(self.next_float_var_id()))
             }
+            ast::LitKind::Bool(_) => tcx.types.bool
         }
-        if any_diverges && !warned {
-            let parent = self.tcx.map.get_parent_node(args[0].id);
-            self.tcx
-                .sess
-                .add_lint(lint::builtin::UNREACHABLE_CODE,
-                          parent,
-                          sp,
-                          "unreachable call".to_string());
-            warned = true;
-        }
-
     }
 
-    // We also need to make sure we at least write the ty of the other
-    // arguments which we skipped above.
-    if variadic {
-        for arg in args.iter().skip(expected_arg_count) {
-            self.check_expr(&arg);
-
-            // There are a few types which get autopromoted when passed via varargs
-            // in C but we just error out instead and require explicit casts.
-            let arg_ty = self.structurally_resolved_type(arg.span,
-                                                         self.expr_ty(&arg));
-            match arg_ty.sty {
-                ty::TyFloat(ast::FloatTy::F32) => {
-                    self.type_error_message(arg.span, |t| {
-                        format!("can't pass an `{}` to variadic \
-                                 function, cast to `c_double`", t)
-                    }, arg_ty, None);
-                }
-                ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => {
-                    self.type_error_message(arg.span, |t| {
-                        format!("can't pass `{}` to variadic \
-                                 function, cast to `c_int`",
-                                       t)
-                    }, arg_ty, None);
-                }
-                ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => {
-                    self.type_error_message(arg.span, |t| {
-                        format!("can't pass `{}` to variadic \
-                                 function, cast to `c_uint`",
-                                       t)
-                    }, arg_ty, None);
-                }
-                ty::TyFnDef(_, _, f) => {
-                    let ptr_ty = self.tcx.mk_fn_ptr(f);
-                    let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty);
-                    self.type_error_message(arg.span,
-                                            |t| {
-                        format!("can't pass `{}` to variadic \
-                                 function, cast to `{}`", t, ptr_ty)
-                    }, arg_ty, None);
-                }
-                _ => {}
-            }
-        }
+    fn check_expr_eq_type(&self,
+                          expr: &'gcx hir::Expr,
+                          expected: Ty<'tcx>) {
+        self.check_expr_with_hint(expr, expected);
+        self.demand_eqtype(expr.span, expected, self.expr_ty(expr));
     }
-}
 
-fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
-    (0..len).map(|_| self.tcx.types.err).collect()
-}
-
-fn write_call(&self,
-              call_expr: &hir::Expr,
-              output: ty::FnOutput<'tcx>) {
-    self.write_ty(call_expr.id, match output {
-        ty::FnConverging(output_ty) => output_ty,
-        ty::FnDiverging => self.next_diverging_ty_var()
-    });
-}
-
-// AST fragment checking
-fn check_lit(&self,
-             lit: &ast::Lit,
-             expected: Expectation<'tcx>)
-             -> Ty<'tcx>
-{
-    let tcx = self.tcx;
-
-    match lit.node {
-        ast::LitKind::Str(..) => tcx.mk_static_str(),
-        ast::LitKind::ByteStr(ref v) => {
-            tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
-                            tcx.mk_array(tcx.types.u8, v.len()))
-        }
-        ast::LitKind::Byte(_) => tcx.types.u8,
-        ast::LitKind::Char(_) => tcx.types.char,
-        ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
-        ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
-        ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
-            let opt_ty = expected.to_option(self).and_then(|ty| {
-                match ty.sty {
-                    ty::TyInt(_) | ty::TyUint(_) => Some(ty),
-                    ty::TyChar => Some(tcx.types.u8),
-                    ty::TyRawPtr(..) => Some(tcx.types.usize),
-                    ty::TyFnDef(..) | ty::TyFnPtr(_) => Some(tcx.types.usize),
-                    _ => None
-                }
-            });
-            opt_ty.unwrap_or_else(
-                || tcx.mk_int_var(self.next_int_var_id()))
-        }
-        ast::LitKind::Float(_, t) => tcx.mk_mach_float(t),
-        ast::LitKind::FloatUnsuffixed(_) => {
-            let opt_ty = expected.to_option(self).and_then(|ty| {
-                match ty.sty {
-                    ty::TyFloat(_) => Some(ty),
-                    _ => None
-                }
-            });
-            opt_ty.unwrap_or_else(
-                || tcx.mk_float_var(self.next_float_var_id()))
-        }
-        ast::LitKind::Bool(_) => tcx.types.bool
-    }
-}
-
-fn check_expr_eq_type(&self,
-                      expr: &'gcx hir::Expr,
-                      expected: Ty<'tcx>) {
-    self.check_expr_with_hint(expr, expected);
-    self.demand_eqtype(expr.span, expected, self.expr_ty(expr));
-}
-
-pub fn check_expr_has_type(&self,
-                           expr: &'gcx hir::Expr,
-                           expected: Ty<'tcx>) {
-    self.check_expr_with_hint(expr, expected);
-    self.demand_suptype(expr.span, expected, self.expr_ty(expr));
-}
-
-fn check_expr_coercable_to_type(&self,
-                                expr: &'gcx hir::Expr,
-                                expected: Ty<'tcx>) {
-    self.check_expr_with_hint(expr, expected);
-    self.demand_coerce(expr, expected);
-}
-
-fn check_expr_with_hint(&self, expr: &'gcx hir::Expr,
-                        expected: Ty<'tcx>) {
-    self.check_expr_with_expectation(expr, ExpectHasType(expected))
-}
-
-fn check_expr_with_expectation(&self,
+    pub fn check_expr_has_type(&self,
                                expr: &'gcx hir::Expr,
-                               expected: Expectation<'tcx>) {
-    self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference)
-}
+                               expected: Ty<'tcx>) {
+        self.check_expr_with_hint(expr, expected);
+        self.demand_suptype(expr.span, expected, self.expr_ty(expr));
+    }
 
-fn check_expr(&self, expr: &'gcx hir::Expr)  {
-    self.check_expr_with_expectation(expr, NoExpectation)
-}
+    fn check_expr_coercable_to_type(&self,
+                                    expr: &'gcx hir::Expr,
+                                    expected: Ty<'tcx>) {
+        self.check_expr_with_hint(expr, expected);
+        self.demand_coerce(expr, expected);
+    }
 
-fn check_expr_with_lvalue_pref(&self, expr: &'gcx hir::Expr,
-                               lvalue_pref: LvaluePreference)  {
-    self.check_expr_with_expectation_and_lvalue_pref(expr, NoExpectation, lvalue_pref)
-}
+    fn check_expr_with_hint(&self, expr: &'gcx hir::Expr,
+                            expected: Ty<'tcx>) {
+        self.check_expr_with_expectation(expr, ExpectHasType(expected))
+    }
 
-// determine the `self` type, using fresh variables for all variables
-// declared on the impl declaration e.g., `impl<A,B> for Vec<(A,B)>`
-// would return ($0, $1) where $0 and $1 are freshly instantiated type
-// variables.
-pub fn impl_self_ty(&self,
-                    span: Span, // (potential) receiver for this impl
-                    did: DefId)
-                    -> TypeAndSubsts<'tcx> {
-    let tcx = self.tcx;
+    fn check_expr_with_expectation(&self,
+                                   expr: &'gcx hir::Expr,
+                                   expected: Expectation<'tcx>) {
+        self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference)
+    }
 
-    let ity = tcx.lookup_item_type(did);
-    let (tps, rps, raw_ty) =
-        (ity.generics.types.get_slice(subst::TypeSpace),
-         ity.generics.regions.get_slice(subst::TypeSpace),
-         ity.ty);
+    fn check_expr(&self, expr: &'gcx hir::Expr)  {
+        self.check_expr_with_expectation(expr, NoExpectation)
+    }
 
-    debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty);
+    fn check_expr_with_lvalue_pref(&self, expr: &'gcx hir::Expr,
+                                   lvalue_pref: LvaluePreference)  {
+        self.check_expr_with_expectation_and_lvalue_pref(expr, NoExpectation, lvalue_pref)
+    }
 
-    let rps = self.region_vars_for_defs(span, rps);
-    let mut substs = subst::Substs::new(
-        VecPerParamSpace::empty(),
-        VecPerParamSpace::new(rps, Vec::new(), Vec::new()));
-    self.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps);
-    let substd_ty = self.instantiate_type_scheme(span, &substs, &raw_ty);
+    // determine the `self` type, using fresh variables for all variables
+    // declared on the impl declaration e.g., `impl<A,B> for Vec<(A,B)>`
+    // would return ($0, $1) where $0 and $1 are freshly instantiated type
+    // variables.
+    pub fn impl_self_ty(&self,
+                        span: Span, // (potential) receiver for this impl
+                        did: DefId)
+                        -> TypeAndSubsts<'tcx> {
+        let tcx = self.tcx;
 
-    TypeAndSubsts { substs: substs, ty: substd_ty }
-}
+        let ity = tcx.lookup_item_type(did);
+        let (tps, rps, raw_ty) =
+            (ity.generics.types.get_slice(subst::TypeSpace),
+             ity.generics.regions.get_slice(subst::TypeSpace),
+             ity.ty);
 
-/// Unifies the return type with the expected type early, for more coercions
-/// and forward type information on the argument expressions.
-fn expected_types_for_fn_args(&self,
-                              call_span: Span,
-                              expected_ret: Expectation<'tcx>,
-                              formal_ret: ty::FnOutput<'tcx>,
-                              formal_args: &[Ty<'tcx>])
-                              -> Vec<Ty<'tcx>> {
-    let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| {
-        if let ty::FnConverging(formal_ret_ty) = formal_ret {
-            self.commit_regions_if_ok(|| {
-                // Attempt to apply a subtyping relationship between the formal
-                // return type (likely containing type variables if the function
-                // is polymorphic) and the expected return type.
-                // No argument expectations are produced if unification fails.
-                let origin = TypeOrigin::Misc(call_span);
-                let ures = self.sub_types(false, origin, formal_ret_ty, ret_ty);
-                // FIXME(#15760) can't use try! here, FromError doesn't default
-                // to identity so the resulting type is not constrained.
-                match ures {
-                    // FIXME(#32730) propagate obligations
-                    Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
-                    Err(e) => return Err(e),
-                }
+        debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty);
 
-                // Record all the argument types, with the substitutions
-                // produced from the above subtyping unification.
-                Ok(formal_args.iter().map(|ty| {
-                    self.resolve_type_vars_if_possible(ty)
-                }).collect())
-            }).ok()
-        } else {
-            None
-        }
-    }).unwrap_or(vec![]);
-    debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})",
-           formal_args, formal_ret,
-           expected_args, expected_ret);
-    expected_args
-}
+        let rps = self.region_vars_for_defs(span, rps);
+        let mut substs = subst::Substs::new(
+            VecPerParamSpace::empty(),
+            VecPerParamSpace::new(rps, Vec::new(), Vec::new()));
+        self.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps);
+        let substd_ty = self.instantiate_type_scheme(span, &substs, &raw_ty);
+
+        TypeAndSubsts { substs: substs, ty: substd_ty }
+    }
+
+    /// Unifies the return type with the expected type early, for more coercions
+    /// and forward type information on the argument expressions.
+    fn expected_types_for_fn_args(&self,
+                                  call_span: Span,
+                                  expected_ret: Expectation<'tcx>,
+                                  formal_ret: ty::FnOutput<'tcx>,
+                                  formal_args: &[Ty<'tcx>])
+                                  -> Vec<Ty<'tcx>> {
+        let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| {
+            if let ty::FnConverging(formal_ret_ty) = formal_ret {
+                self.commit_regions_if_ok(|| {
+                    // Attempt to apply a subtyping relationship between the formal
+                    // return type (likely containing type variables if the function
+                    // is polymorphic) and the expected return type.
+                    // No argument expectations are produced if unification fails.
+                    let origin = TypeOrigin::Misc(call_span);
+                    let ures = self.sub_types(false, origin, formal_ret_ty, ret_ty);
+                    // FIXME(#15760) can't use try! here, FromError doesn't default
+                    // to identity so the resulting type is not constrained.
+                    match ures {
+                        // FIXME(#32730) propagate obligations
+                        Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
+                        Err(e) => return Err(e),
+                    }
+
+                    // Record all the argument types, with the substitutions
+                    // produced from the above subtyping unification.
+                    Ok(formal_args.iter().map(|ty| {
+                        self.resolve_type_vars_if_possible(ty)
+                    }).collect())
+                }).ok()
+            } else {
+                None
+            }
+        }).unwrap_or(vec![]);
+        debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})",
+               formal_args, formal_ret,
+               expected_args, expected_ret);
+        expected_args
+    }
 
     // Checks a method call.
     fn check_method_call(&self,
@@ -3319,1078 +3323,1080 @@ fn expected_types_for_fn_args(&self,
     }
 
 
-/// Invariant:
-/// If an expression has any sub-expressions that result in a type error,
-/// inspecting that expression's type with `ty.references_error()` will return
-/// true. Likewise, if an expression is known to diverge, inspecting its
-/// type with `ty::type_is_bot` will return true (n.b.: since Rust is
-/// strict, _|_ can appear in the type of an expression that does not,
-/// itself, diverge: for example, fn() -> _|_.)
-/// Note that inspecting a type's structure *directly* may expose the fact
-/// that there are actually multiple representations for `TyError`, so avoid
-/// that when err needs to be handled differently.
-fn check_expr_with_expectation_and_lvalue_pref(&self,
-                                               expr: &'gcx hir::Expr,
-                                               expected: Expectation<'tcx>,
-                                               lvalue_pref: LvaluePreference) {
-    debug!(">> typechecking: expr={:?} expected={:?}",
-           expr, expected);
-
-    let tcx = self.tcx;
-    let id = expr.id;
-    match expr.node {
-      hir::ExprBox(ref subexpr) => {
-        let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| {
-            match ty.sty {
-                ty::TyBox(ty) => Expectation::rvalue_hint(self, ty),
-                _ => NoExpectation
-            }
-        });
-        self.check_expr_with_expectation(subexpr, expected_inner);
-        let referent_ty = self.expr_ty(&subexpr);
-        self.write_ty(id, tcx.mk_box(referent_ty));
-      }
-
-      hir::ExprLit(ref lit) => {
-        let typ = self.check_lit(&lit, expected);
-        self.write_ty(id, typ);
-      }
-      hir::ExprBinary(op, ref lhs, ref rhs) => {
-        self.check_binop(expr, op, lhs, rhs);
-      }
-      hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-        self.check_binop_assign(expr, op, lhs, rhs);
-      }
-      hir::ExprUnary(unop, ref oprnd) => {
-        let expected_inner = match unop {
-            hir::UnNot | hir::UnNeg => {
-                expected
-            }
-            hir::UnDeref => {
-                NoExpectation
-            }
-        };
-        let lvalue_pref = match unop {
-            hir::UnDeref => lvalue_pref,
-            _ => NoPreference
-        };
-        self.check_expr_with_expectation_and_lvalue_pref(&oprnd,
-                                                         expected_inner,
-                                                         lvalue_pref);
-        let mut oprnd_t = self.expr_ty(&oprnd);
-
-        if !oprnd_t.references_error() {
-            match unop {
-                hir::UnDeref => {
-                    oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
-
-                    if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) {
-                        oprnd_t = mt.ty;
-                    } else if let Some(method) = self.try_overloaded_deref(
-                            expr.span, Some(&oprnd), oprnd_t, lvalue_pref) {
-                        oprnd_t = self.make_overloaded_lvalue_return_type(method).ty;
-                        self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
-                                                                       method);
-                    } else {
-                        self.type_error_message(expr.span, |actual| {
-                            format!("type `{}` cannot be \
-                                    dereferenced", actual)
-                        }, oprnd_t, None);
-                        oprnd_t = tcx.types.err;
-                    }
-                }
-                hir::UnNot => {
-                    oprnd_t = self.structurally_resolved_type(oprnd.span,
-                                                              oprnd_t);
-                    if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) {
-                        oprnd_t = self.check_user_unop("!", "not",
-                                                       tcx.lang_items.not_trait(),
-                                                       expr, &oprnd, oprnd_t, unop);
-                    }
-                }
-                hir::UnNeg => {
-                    oprnd_t = self.structurally_resolved_type(oprnd.span,
-                                                              oprnd_t);
-                    if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
-                        oprnd_t = self.check_user_unop("-", "neg",
-                                                       tcx.lang_items.neg_trait(),
-                                                       expr, &oprnd, oprnd_t, unop);
-                    }
-                }
-            }
-        }
-        self.write_ty(id, oprnd_t);
-      }
-      hir::ExprAddrOf(mutbl, ref oprnd) => {
-        let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
-            match ty.sty {
-                ty::TyRef(_, ref mt) | ty::TyRawPtr(ref mt) => {
-                    if self.tcx.expr_is_lval(&oprnd) {
-                        // Lvalues may legitimately have unsized types.
-                        // For example, dereferences of a fat pointer and
-                        // the last field of a struct can be unsized.
-                        ExpectHasType(mt.ty)
-                    } else {
-                        Expectation::rvalue_hint(self, mt.ty)
-                    }
-                }
-                _ => NoExpectation
-            }
-        });
-        let lvalue_pref = LvaluePreference::from_mutbl(mutbl);
-        self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
-
-        let tm = ty::TypeAndMut { ty: self.expr_ty(&oprnd), mutbl: mutbl };
-        let oprnd_t = if tm.ty.references_error() {
-            tcx.types.err
-        } else {
-            // Note: at this point, we cannot say what the best lifetime
-            // is to use for resulting pointer.  We want to use the
-            // shortest lifetime possible so as to avoid spurious borrowck
-            // errors.  Moreover, the longest lifetime will depend on the
-            // precise details of the value whose address is being taken
-            // (and how long it is valid), which we don't know yet until type
-            // inference is complete.
-            //
-            // Therefore, here we simply generate a region variable.  The
-            // region inferencer will then select the ultimate value.
-            // Finally, borrowck is charged with guaranteeing that the
-            // value whose address was taken can actually be made to live
-            // as long as it needs to live.
-            let region = self.next_region_var(infer::AddrOfRegion(expr.span));
-            tcx.mk_ref(tcx.mk_region(region), tm)
-        };
-        self.write_ty(id, oprnd_t);
-      }
-      hir::ExprPath(ref maybe_qself, ref path) => {
-          let opt_self_ty = maybe_qself.as_ref().map(|qself| {
-              self.to_ty(&qself.ty)
-          });
-
-          let path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) {
-              d
-          } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
-                // Create some fake resolution that can't possibly be a type.
-                def::PathResolution {
-                    base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
-                    depth: path.segments.len()
-                }
-            } else {
-              span_bug!(expr.span, "unbound path {:?}", expr)
-          };
-
-          if let Some((opt_ty, segments, def)) =
-                  self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path,
-                                               expr.span, expr.id) {
-              if def != Def::Err {
-                  let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
-                                                                                     def);
-                  self.instantiate_path(segments, scheme, &predicates,
-                                        opt_ty, def, expr.span, id);
-              } else {
-                  self.set_tainted_by_errors();
-                  self.write_ty(id, self.tcx.types.err);
-              }
-          }
-
-          // We always require that the type provided as the value for
-          // a type parameter outlives the moment of instantiation.
-          self.opt_node_ty_substs(expr.id, |item_substs| {
-              self.add_wf_bounds(&item_substs.substs, expr);
-          });
-      }
-      hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
-          for output in outputs {
-              self.check_expr(output);
-          }
-          for input in inputs {
-              self.check_expr(input);
-          }
-          self.write_nil(id);
-      }
-      hir::ExprBreak(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
-      hir::ExprAgain(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
-      hir::ExprRet(ref expr_opt) => {
-        match self.ret_ty {
-            ty::FnConverging(result_type) => {
-                if let Some(ref e) = *expr_opt {
-                    self.check_expr_coercable_to_type(&e, result_type);
-                } else {
-                    let eq_result = self.eq_types(false,
-                                                  TypeOrigin::Misc(expr.span),
-                                                  result_type,
-                                                  tcx.mk_nil())
-                        // FIXME(#32730) propagate obligations
-                        .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()));
-                    if eq_result.is_err() {
-                        span_err!(tcx.sess, expr.span, E0069,
-                                  "`return;` in a function whose return type is not `()`");
-                    }
-                }
-            }
-            ty::FnDiverging => {
-                if let Some(ref e) = *expr_opt {
-                    self.check_expr(&e);
-                }
-                span_err!(tcx.sess, expr.span, E0166,
-                    "`return` in a function declared as diverging");
-            }
-        }
-        self.write_ty(id, self.next_diverging_ty_var());
-      }
-      hir::ExprAssign(ref lhs, ref rhs) => {
-        self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
+    /// Invariant:
+    /// If an expression has any sub-expressions that result in a type error,
+    /// inspecting that expression's type with `ty.references_error()` will return
+    /// true. Likewise, if an expression is known to diverge, inspecting its
+    /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
+    /// strict, _|_ can appear in the type of an expression that does not,
+    /// itself, diverge: for example, fn() -> _|_.)
+    /// Note that inspecting a type's structure *directly* may expose the fact
+    /// that there are actually multiple representations for `TyError`, so avoid
+    /// that when err needs to be handled differently.
+    fn check_expr_with_expectation_and_lvalue_pref(&self,
+                                                   expr: &'gcx hir::Expr,
+                                                   expected: Expectation<'tcx>,
+                                                   lvalue_pref: LvaluePreference) {
+        debug!(">> typechecking: expr={:?} expected={:?}",
+               expr, expected);
 
         let tcx = self.tcx;
-        if !tcx.expr_is_lval(&lhs) {
-            span_err!(tcx.sess, expr.span, E0070,
-                "invalid left-hand side expression");
-        }
-
-        let lhs_ty = self.expr_ty(&lhs);
-        self.check_expr_coercable_to_type(&rhs, lhs_ty);
-        let rhs_ty = self.expr_ty(&rhs);
-
-        self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized);
-
-        if lhs_ty.references_error() || rhs_ty.references_error() {
-            self.write_error(id);
-        } else {
-            self.write_nil(id);
-        }
-      }
-      hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => {
-        self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
-                             id, expr.span, expected);
-      }
-      hir::ExprWhile(ref cond, ref body, _) => {
-        self.check_expr_has_type(&cond, tcx.types.bool);
-        self.check_block_no_value(&body);
-        let cond_ty = self.expr_ty(&cond);
-        let body_ty = self.node_ty(body.id);
-        if cond_ty.references_error() || body_ty.references_error() {
-            self.write_error(id);
-        }
-        else {
-            self.write_nil(id);
-        }
-      }
-      hir::ExprLoop(ref body, _) => {
-        self.check_block_no_value(&body);
-        if !may_break(tcx, expr.id, &body) {
-            self.write_ty(id, self.next_diverging_ty_var());
-        } else {
-            self.write_nil(id);
-        }
-      }
-      hir::ExprMatch(ref discrim, ref arms, match_src) => {
-        self.check_match(expr, &discrim, arms, expected, match_src);
-      }
-      hir::ExprClosure(capture, ref decl, ref body, _) => {
-          self.check_expr_closure(expr, capture, &decl, &body, expected);
-      }
-      hir::ExprBlock(ref b) => {
-        self.check_block_with_expected(&b, expected);
-        self.write_ty(id, self.node_ty(b.id));
-      }
-      hir::ExprCall(ref callee, ref args) => {
-          self.check_call(expr, &callee, &args[..], expected);
-
-          // we must check that return type of called functions is WF:
-          let ret_ty = self.expr_ty(expr);
-          self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
-      }
-      hir::ExprMethodCall(name, ref tps, ref args) => {
-          self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
-          let arg_tys = args.iter().map(|a| self.expr_ty(&a));
-          let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error());
-          if args_err {
-              self.write_error(id);
+        let id = expr.id;
+        match expr.node {
+          hir::ExprBox(ref subexpr) => {
+            let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| {
+                match ty.sty {
+                    ty::TyBox(ty) => Expectation::rvalue_hint(self, ty),
+                    _ => NoExpectation
+                }
+            });
+            self.check_expr_with_expectation(subexpr, expected_inner);
+            let referent_ty = self.expr_ty(&subexpr);
+            self.write_ty(id, tcx.mk_box(referent_ty));
           }
-      }
-      hir::ExprCast(ref e, ref t) => {
-        if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {
-            self.check_expr_with_hint(&count_expr, tcx.types.usize);
-        }
 
-        // Find the type of `e`. Supply hints based on the type we are casting to,
-        // if appropriate.
-        let t_cast = self.to_ty(t);
-        let t_cast = self.resolve_type_vars_if_possible(&t_cast);
-        self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
-        let t_expr = self.expr_ty(e);
-        let t_cast = self.resolve_type_vars_if_possible(&t_cast);
-
-        // Eagerly check for some obvious errors.
-        if t_expr.references_error() || t_cast.references_error() {
-            self.write_error(id);
-        } else {
-            // Write a type for the whole expression, assuming everything is going
-            // to work out Ok.
-            self.write_ty(id, t_cast);
-
-            // Defer other checks until we're done type checking.
-            let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
-            match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
-                Ok(cast_check) => {
-                    deferred_cast_checks.push(cast_check);
+          hir::ExprLit(ref lit) => {
+            let typ = self.check_lit(&lit, expected);
+            self.write_ty(id, typ);
+          }
+          hir::ExprBinary(op, ref lhs, ref rhs) => {
+            self.check_binop(expr, op, lhs, rhs);
+          }
+          hir::ExprAssignOp(op, ref lhs, ref rhs) => {
+            self.check_binop_assign(expr, op, lhs, rhs);
+          }
+          hir::ExprUnary(unop, ref oprnd) => {
+            let expected_inner = match unop {
+                hir::UnNot | hir::UnNeg => {
+                    expected
                 }
-                Err(ErrorReported) => {
-                    self.write_error(id);
+                hir::UnDeref => {
+                    NoExpectation
                 }
-            }
-        }
-      }
-      hir::ExprType(ref e, ref t) => {
-        let typ = self.to_ty(&t);
-        self.check_expr_eq_type(&e, typ);
-        self.write_ty(id, typ);
-      }
-      hir::ExprVec(ref args) => {
-        let uty = expected.to_option(self).and_then(|uty| {
-            match uty.sty {
-                ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty),
-                _ => None
-            }
-        });
-
-        let mut unified = self.next_ty_var();
-        let coerce_to = uty.unwrap_or(unified);
-
-        for (i, e) in args.iter().enumerate() {
-            self.check_expr_with_hint(e, coerce_to);
-            let e_ty = self.expr_ty(e);
-            let origin = TypeOrigin::Misc(e.span);
-
-            // Special-case the first element, as it has no "previous expressions".
-            let result = if i == 0 {
-                self.try_coerce(e, coerce_to)
-            } else {
-                let prev_elems = || args[..i].iter().map(|e| &**e);
-                self.try_find_coercion_lub(origin, prev_elems, unified, e)
             };
+            let lvalue_pref = match unop {
+                hir::UnDeref => lvalue_pref,
+                _ => NoPreference
+            };
+            self.check_expr_with_expectation_and_lvalue_pref(&oprnd,
+                                                             expected_inner,
+                                                             lvalue_pref);
+            let mut oprnd_t = self.expr_ty(&oprnd);
 
-            match result {
-                Ok(ty) => unified = ty,
-                Err(e) => {
-                    self.report_mismatched_types(origin, unified, e_ty, e);
+            if !oprnd_t.references_error() {
+                match unop {
+                    hir::UnDeref => {
+                        oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
+
+                        if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) {
+                            oprnd_t = mt.ty;
+                        } else if let Some(method) = self.try_overloaded_deref(
+                                expr.span, Some(&oprnd), oprnd_t, lvalue_pref) {
+                            oprnd_t = self.make_overloaded_lvalue_return_type(method).ty;
+                            self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
+                                                                           method);
+                        } else {
+                            self.type_error_message(expr.span, |actual| {
+                                format!("type `{}` cannot be \
+                                        dereferenced", actual)
+                            }, oprnd_t, None);
+                            oprnd_t = tcx.types.err;
+                        }
+                    }
+                    hir::UnNot => {
+                        oprnd_t = self.structurally_resolved_type(oprnd.span,
+                                                                  oprnd_t);
+                        if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) {
+                            oprnd_t = self.check_user_unop("!", "not",
+                                                           tcx.lang_items.not_trait(),
+                                                           expr, &oprnd, oprnd_t, unop);
+                        }
+                    }
+                    hir::UnNeg => {
+                        oprnd_t = self.structurally_resolved_type(oprnd.span,
+                                                                  oprnd_t);
+                        if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
+                            oprnd_t = self.check_user_unop("-", "neg",
+                                                           tcx.lang_items.neg_trait(),
+                                                           expr, &oprnd, oprnd_t, unop);
+                        }
+                    }
                 }
             }
-        }
-        self.write_ty(id, tcx.mk_array(unified, args.len()));
-      }
-      hir::ExprRepeat(ref element, ref count_expr) => {
-        self.check_expr_has_type(&count_expr, tcx.types.usize);
-        let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr);
+            self.write_ty(id, oprnd_t);
+          }
+          hir::ExprAddrOf(mutbl, ref oprnd) => {
+            let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
+                match ty.sty {
+                    ty::TyRef(_, ref mt) | ty::TyRawPtr(ref mt) => {
+                        if self.tcx.expr_is_lval(&oprnd) {
+                            // Lvalues may legitimately have unsized types.
+                            // For example, dereferences of a fat pointer and
+                            // the last field of a struct can be unsized.
+                            ExpectHasType(mt.ty)
+                        } else {
+                            Expectation::rvalue_hint(self, mt.ty)
+                        }
+                    }
+                    _ => NoExpectation
+                }
+            });
+            let lvalue_pref = LvaluePreference::from_mutbl(mutbl);
+            self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
 
-        let uty = match expected {
-            ExpectHasType(uty) => {
+            let tm = ty::TypeAndMut { ty: self.expr_ty(&oprnd), mutbl: mutbl };
+            let oprnd_t = if tm.ty.references_error() {
+                tcx.types.err
+            } else {
+                // Note: at this point, we cannot say what the best lifetime
+                // is to use for resulting pointer.  We want to use the
+                // shortest lifetime possible so as to avoid spurious borrowck
+                // errors.  Moreover, the longest lifetime will depend on the
+                // precise details of the value whose address is being taken
+                // (and how long it is valid), which we don't know yet until type
+                // inference is complete.
+                //
+                // Therefore, here we simply generate a region variable.  The
+                // region inferencer will then select the ultimate value.
+                // Finally, borrowck is charged with guaranteeing that the
+                // value whose address was taken can actually be made to live
+                // as long as it needs to live.
+                let region = self.next_region_var(infer::AddrOfRegion(expr.span));
+                tcx.mk_ref(tcx.mk_region(region), tm)
+            };
+            self.write_ty(id, oprnd_t);
+          }
+          hir::ExprPath(ref maybe_qself, ref path) => {
+              let opt_self_ty = maybe_qself.as_ref().map(|qself| {
+                  self.to_ty(&qself.ty)
+              });
+
+              let path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) {
+                  d
+              } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
+                    // Create some fake resolution that can't possibly be a type.
+                    def::PathResolution {
+                        base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
+                        depth: path.segments.len()
+                    }
+                } else {
+                  span_bug!(expr.span, "unbound path {:?}", expr)
+              };
+
+              if let Some((opt_ty, segments, def)) =
+                      self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path,
+                                                   expr.span, expr.id) {
+                  if def != Def::Err {
+                      let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
+                                                                                         def);
+                      self.instantiate_path(segments, scheme, &predicates,
+                                            opt_ty, def, expr.span, id);
+                  } else {
+                      self.set_tainted_by_errors();
+                      self.write_ty(id, self.tcx.types.err);
+                  }
+              }
+
+              // We always require that the type provided as the value for
+              // a type parameter outlives the moment of instantiation.
+              self.opt_node_ty_substs(expr.id, |item_substs| {
+                  self.add_wf_bounds(&item_substs.substs, expr);
+              });
+          }
+          hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
+              for output in outputs {
+                  self.check_expr(output);
+              }
+              for input in inputs {
+                  self.check_expr(input);
+              }
+              self.write_nil(id);
+          }
+          hir::ExprBreak(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
+          hir::ExprAgain(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
+          hir::ExprRet(ref expr_opt) => {
+            match self.ret_ty {
+                ty::FnConverging(result_type) => {
+                    if let Some(ref e) = *expr_opt {
+                        self.check_expr_coercable_to_type(&e, result_type);
+                    } else {
+                        let eq_result = self.eq_types(false,
+                                                      TypeOrigin::Misc(expr.span),
+                                                      result_type,
+                                                      tcx.mk_nil())
+                            // FIXME(#32730) propagate obligations
+                            .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()));
+                        if eq_result.is_err() {
+                            span_err!(tcx.sess, expr.span, E0069,
+                                      "`return;` in a function whose return type is not `()`");
+                        }
+                    }
+                }
+                ty::FnDiverging => {
+                    if let Some(ref e) = *expr_opt {
+                        self.check_expr(&e);
+                    }
+                    span_err!(tcx.sess, expr.span, E0166,
+                        "`return` in a function declared as diverging");
+                }
+            }
+            self.write_ty(id, self.next_diverging_ty_var());
+          }
+          hir::ExprAssign(ref lhs, ref rhs) => {
+            self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
+
+            let tcx = self.tcx;
+            if !tcx.expr_is_lval(&lhs) {
+                span_err!(tcx.sess, expr.span, E0070,
+                    "invalid left-hand side expression");
+            }
+
+            let lhs_ty = self.expr_ty(&lhs);
+            self.check_expr_coercable_to_type(&rhs, lhs_ty);
+            let rhs_ty = self.expr_ty(&rhs);
+
+            self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized);
+
+            if lhs_ty.references_error() || rhs_ty.references_error() {
+                self.write_error(id);
+            } else {
+                self.write_nil(id);
+            }
+          }
+          hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => {
+            self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
+                                 id, expr.span, expected);
+          }
+          hir::ExprWhile(ref cond, ref body, _) => {
+            self.check_expr_has_type(&cond, tcx.types.bool);
+            self.check_block_no_value(&body);
+            let cond_ty = self.expr_ty(&cond);
+            let body_ty = self.node_ty(body.id);
+            if cond_ty.references_error() || body_ty.references_error() {
+                self.write_error(id);
+            }
+            else {
+                self.write_nil(id);
+            }
+          }
+          hir::ExprLoop(ref body, _) => {
+            self.check_block_no_value(&body);
+            if !may_break(tcx, expr.id, &body) {
+                self.write_ty(id, self.next_diverging_ty_var());
+            } else {
+                self.write_nil(id);
+            }
+          }
+          hir::ExprMatch(ref discrim, ref arms, match_src) => {
+            self.check_match(expr, &discrim, arms, expected, match_src);
+          }
+          hir::ExprClosure(capture, ref decl, ref body, _) => {
+              self.check_expr_closure(expr, capture, &decl, &body, expected);
+          }
+          hir::ExprBlock(ref b) => {
+            self.check_block_with_expected(&b, expected);
+            self.write_ty(id, self.node_ty(b.id));
+          }
+          hir::ExprCall(ref callee, ref args) => {
+              self.check_call(expr, &callee, &args[..], expected);
+
+              // we must check that return type of called functions is WF:
+              let ret_ty = self.expr_ty(expr);
+              self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
+          }
+          hir::ExprMethodCall(name, ref tps, ref args) => {
+              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
+              let arg_tys = args.iter().map(|a| self.expr_ty(&a));
+              let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error());
+              if args_err {
+                  self.write_error(id);
+              }
+          }
+          hir::ExprCast(ref e, ref t) => {
+            if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {
+                self.check_expr_with_hint(&count_expr, tcx.types.usize);
+            }
+
+            // Find the type of `e`. Supply hints based on the type we are casting to,
+            // if appropriate.
+            let t_cast = self.to_ty(t);
+            let t_cast = self.resolve_type_vars_if_possible(&t_cast);
+            self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
+            let t_expr = self.expr_ty(e);
+            let t_cast = self.resolve_type_vars_if_possible(&t_cast);
+
+            // Eagerly check for some obvious errors.
+            if t_expr.references_error() || t_cast.references_error() {
+                self.write_error(id);
+            } else {
+                // Write a type for the whole expression, assuming everything is going
+                // to work out Ok.
+                self.write_ty(id, t_cast);
+
+                // Defer other checks until we're done type checking.
+                let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
+                match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
+                    Ok(cast_check) => {
+                        deferred_cast_checks.push(cast_check);
+                    }
+                    Err(ErrorReported) => {
+                        self.write_error(id);
+                    }
+                }
+            }
+          }
+          hir::ExprType(ref e, ref t) => {
+            let typ = self.to_ty(&t);
+            self.check_expr_eq_type(&e, typ);
+            self.write_ty(id, typ);
+          }
+          hir::ExprVec(ref args) => {
+            let uty = expected.to_option(self).and_then(|uty| {
                 match uty.sty {
                     ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty),
                     _ => None
                 }
-            }
-            _ => None
-        };
+            });
 
-        let (element_ty, t) = match uty {
-            Some(uty) => {
-                self.check_expr_coercable_to_type(&element, uty);
-                (uty, uty)
-            }
-            None => {
-                let t: Ty = self.next_ty_var();
-                self.check_expr_has_type(&element, t);
-                (self.expr_ty(&element), t)
-            }
-        };
+            let mut unified = self.next_ty_var();
+            let coerce_to = uty.unwrap_or(unified);
 
-        if count > 1 {
-            // For [foo, ..n] where n > 1, `foo` must have
-            // Copy type:
-            self.require_type_meets(t, expr.span, traits::RepeatVec, ty::BoundCopy);
-        }
+            for (i, e) in args.iter().enumerate() {
+                self.check_expr_with_hint(e, coerce_to);
+                let e_ty = self.expr_ty(e);
+                let origin = TypeOrigin::Misc(e.span);
 
-        if element_ty.references_error() {
-            self.write_error(id);
-        } else {
-            let t = tcx.mk_array(t, count);
-            self.write_ty(id, t);
-        }
-      }
-      hir::ExprTup(ref elts) => {
-        let flds = expected.only_has_type(self).and_then(|ty| {
-            match ty.sty {
-                ty::TyTuple(ref flds) => Some(&flds[..]),
-                _ => None
-            }
-        });
-        let mut err_field = false;
+                // Special-case the first element, as it has no "previous expressions".
+                let result = if i == 0 {
+                    self.try_coerce(e, coerce_to)
+                } else {
+                    let prev_elems = || args[..i].iter().map(|e| &**e);
+                    self.try_find_coercion_lub(origin, prev_elems, unified, e)
+                };
 
-        let elt_ts = elts.iter().enumerate().map(|(i, e)| {
-            let t = match flds {
-                Some(ref fs) if i < fs.len() => {
-                    let ety = fs[i];
-                    self.check_expr_coercable_to_type(&e, ety);
-                    ety
+                match result {
+                    Ok(ty) => unified = ty,
+                    Err(e) => {
+                        self.report_mismatched_types(origin, unified, e_ty, e);
+                    }
                 }
-                _ => {
-                    self.check_expr_with_expectation(&e, NoExpectation);
-                    self.expr_ty(&e)
+            }
+            self.write_ty(id, tcx.mk_array(unified, args.len()));
+          }
+          hir::ExprRepeat(ref element, ref count_expr) => {
+            self.check_expr_has_type(&count_expr, tcx.types.usize);
+            let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr);
+
+            let uty = match expected {
+                ExpectHasType(uty) => {
+                    match uty.sty {
+                        ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty),
+                        _ => None
+                    }
+                }
+                _ => None
+            };
+
+            let (element_ty, t) = match uty {
+                Some(uty) => {
+                    self.check_expr_coercable_to_type(&element, uty);
+                    (uty, uty)
+                }
+                None => {
+                    let t: Ty = self.next_ty_var();
+                    self.check_expr_has_type(&element, t);
+                    (self.expr_ty(&element), t)
                 }
             };
-            err_field = err_field || t.references_error();
-            t
-        }).collect();
-        if err_field {
-            self.write_error(id);
-        } else {
-            let typ = tcx.mk_tup(elt_ts);
-            self.write_ty(id, typ);
-        }
-      }
-      hir::ExprStruct(ref path, ref fields, ref base_expr) => {
-        self.check_expr_struct(expr, path, fields, base_expr);
 
-        self.require_expr_have_sized_type(expr, traits::StructInitializerSized);
-      }
-      hir::ExprField(ref base, ref field) => {
-        self.check_field(expr, lvalue_pref, &base, field);
-      }
-      hir::ExprTupField(ref base, idx) => {
-        self.check_tup_field(expr, lvalue_pref, &base, idx);
-      }
-      hir::ExprIndex(ref base, ref idx) => {
-          self.check_expr_with_lvalue_pref(&base, lvalue_pref);
-          self.check_expr(&idx);
+            if count > 1 {
+                // For [foo, ..n] where n > 1, `foo` must have
+                // Copy type:
+                self.require_type_meets(t, expr.span, traits::RepeatVec, ty::BoundCopy);
+            }
 
-          let base_t = self.expr_ty(&base);
-          let idx_t = self.expr_ty(&idx);
+            if element_ty.references_error() {
+                self.write_error(id);
+            } else {
+                let t = tcx.mk_array(t, count);
+                self.write_ty(id, t);
+            }
+          }
+          hir::ExprTup(ref elts) => {
+            let flds = expected.only_has_type(self).and_then(|ty| {
+                match ty.sty {
+                    ty::TyTuple(ref flds) => Some(&flds[..]),
+                    _ => None
+                }
+            });
+            let mut err_field = false;
 
-          if base_t.references_error() {
-              self.write_ty(id, base_t);
-          } else if idx_t.references_error() {
-              self.write_ty(id, idx_t);
-          } else {
-              let base_t = self.structurally_resolved_type(expr.span, base_t);
-              match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) {
-                  Some((index_ty, element_ty)) => {
-                      let idx_expr_ty = self.expr_ty(idx);
-                      self.demand_eqtype(expr.span, index_ty, idx_expr_ty);
-                      self.write_ty(id, element_ty);
-                  }
-                  None => {
-                      self.check_expr_has_type(&idx, self.tcx.types.err);
-                      let mut err = self.type_error_struct(
-                          expr.span,
-                          |actual| {
-                              format!("cannot index a value of type `{}`",
-                                      actual)
-                          },
-                          base_t,
-                          None);
-                      // Try to give some advice about indexing tuples.
-                      if let ty::TyTuple(_) = base_t.sty {
-                          let mut needs_note = true;
-                          // If the index is an integer, we can show the actual
-                          // fixed expression:
-                          if let hir::ExprLit(ref lit) = idx.node {
-                              if let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node {
-                                  let snip = tcx.sess.codemap().span_to_snippet(base.span);
-                                  if let Ok(snip) = snip {
-                                      err.span_suggestion(expr.span,
-                                                          "to access tuple elements, use tuple \
-                                                           indexing syntax as shown",
-                                                          format!("{}.{}", snip, i));
-                                      needs_note = false;
+            let elt_ts = elts.iter().enumerate().map(|(i, e)| {
+                let t = match flds {
+                    Some(ref fs) if i < fs.len() => {
+                        let ety = fs[i];
+                        self.check_expr_coercable_to_type(&e, ety);
+                        ety
+                    }
+                    _ => {
+                        self.check_expr_with_expectation(&e, NoExpectation);
+                        self.expr_ty(&e)
+                    }
+                };
+                err_field = err_field || t.references_error();
+                t
+            }).collect();
+            if err_field {
+                self.write_error(id);
+            } else {
+                let typ = tcx.mk_tup(elt_ts);
+                self.write_ty(id, typ);
+            }
+          }
+          hir::ExprStruct(ref path, ref fields, ref base_expr) => {
+            self.check_expr_struct(expr, path, fields, base_expr);
+
+            self.require_expr_have_sized_type(expr, traits::StructInitializerSized);
+          }
+          hir::ExprField(ref base, ref field) => {
+            self.check_field(expr, lvalue_pref, &base, field);
+          }
+          hir::ExprTupField(ref base, idx) => {
+            self.check_tup_field(expr, lvalue_pref, &base, idx);
+          }
+          hir::ExprIndex(ref base, ref idx) => {
+              self.check_expr_with_lvalue_pref(&base, lvalue_pref);
+              self.check_expr(&idx);
+
+              let base_t = self.expr_ty(&base);
+              let idx_t = self.expr_ty(&idx);
+
+              if base_t.references_error() {
+                  self.write_ty(id, base_t);
+              } else if idx_t.references_error() {
+                  self.write_ty(id, idx_t);
+              } else {
+                  let base_t = self.structurally_resolved_type(expr.span, base_t);
+                  match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) {
+                      Some((index_ty, element_ty)) => {
+                          let idx_expr_ty = self.expr_ty(idx);
+                          self.demand_eqtype(expr.span, index_ty, idx_expr_ty);
+                          self.write_ty(id, element_ty);
+                      }
+                      None => {
+                          self.check_expr_has_type(&idx, self.tcx.types.err);
+                          let mut err = self.type_error_struct(
+                              expr.span,
+                              |actual| {
+                                  format!("cannot index a value of type `{}`",
+                                          actual)
+                              },
+                              base_t,
+                              None);
+                          // Try to give some advice about indexing tuples.
+                          if let ty::TyTuple(_) = base_t.sty {
+                              let mut needs_note = true;
+                              // If the index is an integer, we can show the actual
+                              // fixed expression:
+                              if let hir::ExprLit(ref lit) = idx.node {
+                                  if let ast::LitKind::Int(i,
+                                            ast::LitIntType::Unsuffixed) = lit.node {
+                                      let snip = tcx.sess.codemap().span_to_snippet(base.span);
+                                      if let Ok(snip) = snip {
+                                          err.span_suggestion(expr.span,
+                                                              "to access tuple elements, \
+                                                               use tuple indexing syntax \
+                                                               as shown",
+                                                              format!("{}.{}", snip, i));
+                                          needs_note = false;
+                                      }
                                   }
                               }
+                              if needs_note {
+                                  err.help("to access tuple elements, use tuple indexing \
+                                            syntax (e.g. `tuple.0`)");
+                              }
                           }
-                          if needs_note {
-                              err.help("to access tuple elements, use tuple indexing \
-                                        syntax (e.g. `tuple.0`)");
-                          }
+                          err.emit();
+                          self.write_ty(id, self.tcx().types.err);
                       }
-                      err.emit();
-                      self.write_ty(id, self.tcx().types.err);
                   }
               }
-          }
-       }
+           }
+        }
+
+        debug!("type of expr({}) {} is...", expr.id,
+               pprust::expr_to_string(expr));
+        debug!("... {:?}, expected is {:?}",
+               self.expr_ty(expr),
+               expected);
     }
 
-    debug!("type of expr({}) {} is...", expr.id,
-           pprust::expr_to_string(expr));
-    debug!("... {:?}, expected is {:?}",
-           self.expr_ty(expr),
-           expected);
-}
+    pub fn resolve_ty_and_def_ufcs<'b>(&self,
+                                       path_res: def::PathResolution,
+                                       opt_self_ty: Option<Ty<'tcx>>,
+                                       path: &'b hir::Path,
+                                       span: Span,
+                                       node_id: ast::NodeId)
+                                       -> Option<(Option<Ty<'tcx>>, &'b [hir::PathSegment], Def)>
+    {
 
-pub fn resolve_ty_and_def_ufcs<'b>(&self,
-                                   path_res: def::PathResolution,
-                                   opt_self_ty: Option<Ty<'tcx>>,
-                                   path: &'b hir::Path,
-                                   span: Span,
-                                   node_id: ast::NodeId)
-                                   -> Option<(Option<Ty<'tcx>>, &'b [hir::PathSegment], Def)>
-{
-
-    // If fully resolved already, we don't have to do anything.
-    if path_res.depth == 0 {
-        Some((opt_self_ty, &path.segments, path_res.base_def))
-    } else {
-        let mut def = path_res.base_def;
-        let ty_segments = path.segments.split_last().unwrap().1;
-        let base_ty_end = path.segments.len() - path_res.depth;
-        let ty = AstConv::finish_resolving_def_to_ty(self, self, span,
-                                                     PathParamMode::Optional,
-                                                     &mut def,
-                                                     opt_self_ty,
-                                                     &ty_segments[..base_ty_end],
-                                                     &ty_segments[base_ty_end..]);
-        let item_segment = path.segments.last().unwrap();
-        let item_name = item_segment.identifier.name;
-        let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
-            Ok(def) => Some(def),
-            Err(error) => {
-                let def = match error {
-                    method::MethodError::PrivateMatch(def) => Some(def),
-                    _ => None,
-                };
-                if item_name != keywords::Invalid.name() {
-                    self.report_method_error(span, ty, item_name, None, error);
+        // If fully resolved already, we don't have to do anything.
+        if path_res.depth == 0 {
+            Some((opt_self_ty, &path.segments, path_res.base_def))
+        } else {
+            let mut def = path_res.base_def;
+            let ty_segments = path.segments.split_last().unwrap().1;
+            let base_ty_end = path.segments.len() - path_res.depth;
+            let ty = AstConv::finish_resolving_def_to_ty(self, self, span,
+                                                         PathParamMode::Optional,
+                                                         &mut def,
+                                                         opt_self_ty,
+                                                         &ty_segments[..base_ty_end],
+                                                         &ty_segments[base_ty_end..]);
+            let item_segment = path.segments.last().unwrap();
+            let item_name = item_segment.identifier.name;
+            let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
+                Ok(def) => Some(def),
+                Err(error) => {
+                    let def = match error {
+                        method::MethodError::PrivateMatch(def) => Some(def),
+                        _ => None,
+                    };
+                    if item_name != keywords::Invalid.name() {
+                        self.report_method_error(span, ty, item_name, None, error);
+                    }
+                    def
                 }
-                def
+            };
+
+            if let Some(def) = def {
+                // Write back the new resolution.
+                self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution {
+                    base_def: def,
+                    depth: 0,
+                });
+                Some((Some(ty), slice::ref_slice(item_segment), def))
+            } else {
+                self.write_error(node_id);
+                None
             }
+        }
+    }
+
+    pub fn check_decl_initializer(&self,
+                                  local: &'gcx hir::Local,
+                                  init: &'gcx hir::Expr)
+    {
+        let ref_bindings = self.tcx.pat_contains_ref_binding(&local.pat);
+
+        let local_ty = self.local_ty(init.span, local.id);
+        if let Some(m) = ref_bindings {
+            // Somewhat subtle: if we have a `ref` binding in the pattern,
+            // we want to avoid introducing coercions for the RHS. This is
+            // both because it helps preserve sanity and, in the case of
+            // ref mut, for soundness (issue #23116). In particular, in
+            // the latter case, we need to be clear that the type of the
+            // referent for the reference that results is *equal to* the
+            // type of the lvalue it is referencing, and not some
+            // supertype thereof.
+            self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m));
+            let init_ty = self.expr_ty(init);
+            self.demand_eqtype(init.span, init_ty, local_ty);
+        } else {
+            self.check_expr_coercable_to_type(init, local_ty)
+        };
+    }
+
+    pub fn check_decl_local(&self, local: &'gcx hir::Local)  {
+        let tcx = self.tcx;
+
+        let t = self.local_ty(local.span, local.id);
+        self.write_ty(local.id, t);
+
+        if let Some(ref init) = local.init {
+            self.check_decl_initializer(local, &init);
+            let init_ty = self.expr_ty(&init);
+            if init_ty.references_error() {
+                self.write_ty(local.id, init_ty);
+            }
+        }
+
+        let pcx = PatCtxt {
+            fcx: self,
+            map: pat_id_map(&tcx.def_map, &local.pat),
+        };
+        pcx.check_pat(&local.pat, t);
+        let pat_ty = self.node_ty(local.pat.id);
+        if pat_ty.references_error() {
+            self.write_ty(local.id, pat_ty);
+        }
+    }
+
+    pub fn check_stmt(&self, stmt: &'gcx hir::Stmt)  {
+        let node_id;
+        let mut saw_bot = false;
+        let mut saw_err = false;
+        match stmt.node {
+          hir::StmtDecl(ref decl, id) => {
+            node_id = id;
+            match decl.node {
+              hir::DeclLocal(ref l) => {
+                  self.check_decl_local(&l);
+                  let l_t = self.node_ty(l.id);
+                  saw_bot = saw_bot || self.type_var_diverges(l_t);
+                  saw_err = saw_err || l_t.references_error();
+              }
+              hir::DeclItem(_) => {/* ignore for now */ }
+            }
+          }
+          hir::StmtExpr(ref expr, id) => {
+            node_id = id;
+            // Check with expected type of ()
+            self.check_expr_has_type(&expr, self.tcx.mk_nil());
+            let expr_ty = self.expr_ty(&expr);
+            saw_bot = saw_bot || self.type_var_diverges(expr_ty);
+            saw_err = saw_err || expr_ty.references_error();
+          }
+          hir::StmtSemi(ref expr, id) => {
+            node_id = id;
+            self.check_expr(&expr);
+            let expr_ty = self.expr_ty(&expr);
+            saw_bot |= self.type_var_diverges(expr_ty);
+            saw_err |= expr_ty.references_error();
+          }
+        }
+        if saw_bot {
+            self.write_ty(node_id, self.next_diverging_ty_var());
+        }
+        else if saw_err {
+            self.write_error(node_id);
+        }
+        else {
+            self.write_nil(node_id)
+        }
+    }
+
+    pub fn check_block_no_value(&self, blk: &'gcx hir::Block)  {
+        self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil()));
+        let blkty = self.node_ty(blk.id);
+        if blkty.references_error() {
+            self.write_error(blk.id);
+        } else {
+            let nilty = self.tcx.mk_nil();
+            self.demand_suptype(blk.span, nilty, blkty);
+        }
+    }
+
+    fn check_block_with_expected(&self,
+                                 blk: &'gcx hir::Block,
+                                 expected: Expectation<'tcx>) {
+        let prev = {
+            let mut fcx_ps = self.ps.borrow_mut();
+            let unsafety_state = fcx_ps.recurse(blk);
+            replace(&mut *fcx_ps, unsafety_state)
         };
 
-        if let Some(def) = def {
-            // Write back the new resolution.
-            self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution {
-                base_def: def,
-                depth: 0,
-            });
-            Some((Some(ty), slice::ref_slice(item_segment), def))
-        } else {
-            self.write_error(node_id);
-            None
-        }
-    }
-}
-
-pub fn check_decl_initializer(&self,
-                              local: &'gcx hir::Local,
-                              init: &'gcx hir::Expr)
-{
-    let ref_bindings = self.tcx.pat_contains_ref_binding(&local.pat);
-
-    let local_ty = self.local_ty(init.span, local.id);
-    if let Some(m) = ref_bindings {
-        // Somewhat subtle: if we have a `ref` binding in the pattern,
-        // we want to avoid introducing coercions for the RHS. This is
-        // both because it helps preserve sanity and, in the case of
-        // ref mut, for soundness (issue #23116). In particular, in
-        // the latter case, we need to be clear that the type of the
-        // referent for the reference that results is *equal to* the
-        // type of the lvalue it is referencing, and not some
-        // supertype thereof.
-        self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m));
-        let init_ty = self.expr_ty(init);
-        self.demand_eqtype(init.span, init_ty, local_ty);
-    } else {
-        self.check_expr_coercable_to_type(init, local_ty)
-    };
-}
-
-pub fn check_decl_local(&self, local: &'gcx hir::Local)  {
-    let tcx = self.tcx;
-
-    let t = self.local_ty(local.span, local.id);
-    self.write_ty(local.id, t);
-
-    if let Some(ref init) = local.init {
-        self.check_decl_initializer(local, &init);
-        let init_ty = self.expr_ty(&init);
-        if init_ty.references_error() {
-            self.write_ty(local.id, init_ty);
-        }
-    }
-
-    let pcx = PatCtxt {
-        fcx: self,
-        map: pat_id_map(&tcx.def_map, &local.pat),
-    };
-    pcx.check_pat(&local.pat, t);
-    let pat_ty = self.node_ty(local.pat.id);
-    if pat_ty.references_error() {
-        self.write_ty(local.id, pat_ty);
-    }
-}
-
-pub fn check_stmt(&self, stmt: &'gcx hir::Stmt)  {
-    let node_id;
-    let mut saw_bot = false;
-    let mut saw_err = false;
-    match stmt.node {
-      hir::StmtDecl(ref decl, id) => {
-        node_id = id;
-        match decl.node {
-          hir::DeclLocal(ref l) => {
-              self.check_decl_local(&l);
-              let l_t = self.node_ty(l.id);
-              saw_bot = saw_bot || self.type_var_diverges(l_t);
-              saw_err = saw_err || l_t.references_error();
-          }
-          hir::DeclItem(_) => {/* ignore for now */ }
-        }
-      }
-      hir::StmtExpr(ref expr, id) => {
-        node_id = id;
-        // Check with expected type of ()
-        self.check_expr_has_type(&expr, self.tcx.mk_nil());
-        let expr_ty = self.expr_ty(&expr);
-        saw_bot = saw_bot || self.type_var_diverges(expr_ty);
-        saw_err = saw_err || expr_ty.references_error();
-      }
-      hir::StmtSemi(ref expr, id) => {
-        node_id = id;
-        self.check_expr(&expr);
-        let expr_ty = self.expr_ty(&expr);
-        saw_bot |= self.type_var_diverges(expr_ty);
-        saw_err |= expr_ty.references_error();
-      }
-    }
-    if saw_bot {
-        self.write_ty(node_id, self.next_diverging_ty_var());
-    }
-    else if saw_err {
-        self.write_error(node_id);
-    }
-    else {
-        self.write_nil(node_id)
-    }
-}
-
-pub fn check_block_no_value(&self, blk: &'gcx hir::Block)  {
-    self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil()));
-    let blkty = self.node_ty(blk.id);
-    if blkty.references_error() {
-        self.write_error(blk.id);
-    } else {
-        let nilty = self.tcx.mk_nil();
-        self.demand_suptype(blk.span, nilty, blkty);
-    }
-}
-
-fn check_block_with_expected(&self,
-                             blk: &'gcx hir::Block,
-                             expected: Expectation<'tcx>) {
-    let prev = {
-        let mut fcx_ps = self.ps.borrow_mut();
-        let unsafety_state = fcx_ps.recurse(blk);
-        replace(&mut *fcx_ps, unsafety_state)
-    };
-
-    let mut warned = false;
-    let mut any_diverges = false;
-    let mut any_err = false;
-    for s in &blk.stmts {
-        self.check_stmt(s);
-        let s_id = s.node.id();
-        let s_ty = self.node_ty(s_id);
-        if any_diverges && !warned && match s.node {
-            hir::StmtDecl(ref decl, _) => {
-                match decl.node {
-                    hir::DeclLocal(_) => true,
-                    _ => false,
+        let mut warned = false;
+        let mut any_diverges = false;
+        let mut any_err = false;
+        for s in &blk.stmts {
+            self.check_stmt(s);
+            let s_id = s.node.id();
+            let s_ty = self.node_ty(s_id);
+            if any_diverges && !warned && match s.node {
+                hir::StmtDecl(ref decl, _) => {
+                    match decl.node {
+                        hir::DeclLocal(_) => true,
+                        _ => false,
+                    }
                 }
-            }
-            hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true,
-        } {
-            self.tcx
-                .sess
-                .add_lint(lint::builtin::UNREACHABLE_CODE,
-                          s_id,
-                          s.span,
-                          "unreachable statement".to_string());
-            warned = true;
-        }
-        any_diverges = any_diverges || self.type_var_diverges(s_ty);
-        any_err = any_err || s_ty.references_error();
-    }
-    match blk.expr {
-        None => if any_err {
-            self.write_error(blk.id);
-        } else if any_diverges {
-            self.write_ty(blk.id, self.next_diverging_ty_var());
-        } else {
-            self.write_nil(blk.id);
-        },
-        Some(ref e) => {
-            if any_diverges && !warned {
+                hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true,
+            } {
                 self.tcx
                     .sess
                     .add_lint(lint::builtin::UNREACHABLE_CODE,
-                              e.id,
-                              e.span,
-                              "unreachable expression".to_string());
+                              s_id,
+                              s.span,
+                              "unreachable statement".to_string());
+                warned = true;
             }
-            let ety = match expected {
-                ExpectHasType(ety) => {
-                    self.check_expr_coercable_to_type(&e, ety);
-                    ety
-                }
-                _ => {
-                    self.check_expr_with_expectation(&e, expected);
-                    self.expr_ty(&e)
-                }
-            };
-
-            if any_err {
+            any_diverges = any_diverges || self.type_var_diverges(s_ty);
+            any_err = any_err || s_ty.references_error();
+        }
+        match blk.expr {
+            None => if any_err {
                 self.write_error(blk.id);
             } else if any_diverges {
                 self.write_ty(blk.id, self.next_diverging_ty_var());
             } else {
-                self.write_ty(blk.id, ety);
+                self.write_nil(blk.id);
+            },
+            Some(ref e) => {
+                if any_diverges && !warned {
+                    self.tcx
+                        .sess
+                        .add_lint(lint::builtin::UNREACHABLE_CODE,
+                                  e.id,
+                                  e.span,
+                                  "unreachable expression".to_string());
+                }
+                let ety = match expected {
+                    ExpectHasType(ety) => {
+                        self.check_expr_coercable_to_type(&e, ety);
+                        ety
+                    }
+                    _ => {
+                        self.check_expr_with_expectation(&e, expected);
+                        self.expr_ty(&e)
+                    }
+                };
+
+                if any_err {
+                    self.write_error(blk.id);
+                } else if any_diverges {
+                    self.write_ty(blk.id, self.next_diverging_ty_var());
+                } else {
+                    self.write_ty(blk.id, ety);
+                }
             }
-        }
-    };
+        };
 
-    *self.ps.borrow_mut() = prev;
-}
+        *self.ps.borrow_mut() = prev;
+    }
 
 
-fn check_const_with_ty(&self,
-                       _: Span,
-                       e: &'gcx hir::Expr,
-                       declty: Ty<'tcx>) {
-    // Gather locals in statics (because of block expressions).
-    // This is technically unnecessary because locals in static items are forbidden,
-    // but prevents type checking from blowing up before const checking can properly
-    // emit an error.
-    GatherLocalsVisitor { fcx: self }.visit_expr(e);
+    fn check_const_with_ty(&self,
+                           _: Span,
+                           e: &'gcx hir::Expr,
+                           declty: Ty<'tcx>) {
+        // Gather locals in statics (because of block expressions).
+        // This is technically unnecessary because locals in static items are forbidden,
+        // but prevents type checking from blowing up before const checking can properly
+        // emit an error.
+        GatherLocalsVisitor { fcx: self }.visit_expr(e);
 
-    self.check_expr_coercable_to_type(e, declty);
+        self.check_expr_coercable_to_type(e, declty);
 
-    self.select_all_obligations_and_apply_defaults();
-    self.closure_analyze_const(e);
-    self.select_obligations_where_possible();
-    self.check_casts();
-    self.select_all_obligations_or_error();
+        self.select_all_obligations_and_apply_defaults();
+        self.closure_analyze_const(e);
+        self.select_obligations_where_possible();
+        self.check_casts();
+        self.select_all_obligations_or_error();
 
-    self.regionck_expr(e);
-    self.resolve_type_vars_in_expr(e);
-}
+        self.regionck_expr(e);
+        self.resolve_type_vars_in_expr(e);
+    }
 
-// Returns the type parameter count and the type for the given definition.
-fn type_scheme_and_predicates_for_def(&self,
-                                      sp: Span,
-                                      defn: Def)
-                                      -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) {
-    match defn {
-        Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => {
-            let typ = self.local_ty(sp, nid);
-            (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ },
-             ty::GenericPredicates::empty())
-        }
-        Def::Fn(id) | Def::Method(id) |
-        Def::Static(id, _) | Def::Variant(_, id) |
-        Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => {
-            (self.tcx.lookup_item_type(id), self.tcx.lookup_predicates(id))
-        }
-        Def::Trait(_) |
-        Def::Enum(..) |
-        Def::TyAlias(..) |
-        Def::AssociatedTy(..) |
-        Def::PrimTy(_) |
-        Def::TyParam(..) |
-        Def::Mod(..) |
-        Def::ForeignMod(..) |
-        Def::Label(..) |
-        Def::SelfTy(..) |
-        Def::Err => {
-            span_bug!(sp, "expected value, found {:?}", defn);
+    // Returns the type parameter count and the type for the given definition.
+    fn type_scheme_and_predicates_for_def(&self,
+                                          sp: Span,
+                                          defn: Def)
+                                          -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) {
+        match defn {
+            Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => {
+                let typ = self.local_ty(sp, nid);
+                (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ },
+                 ty::GenericPredicates::empty())
+            }
+            Def::Fn(id) | Def::Method(id) |
+            Def::Static(id, _) | Def::Variant(_, id) |
+            Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => {
+                (self.tcx.lookup_item_type(id), self.tcx.lookup_predicates(id))
+            }
+            Def::Trait(_) |
+            Def::Enum(..) |
+            Def::TyAlias(..) |
+            Def::AssociatedTy(..) |
+            Def::PrimTy(_) |
+            Def::TyParam(..) |
+            Def::Mod(..) |
+            Def::ForeignMod(..) |
+            Def::Label(..) |
+            Def::SelfTy(..) |
+            Def::Err => {
+                span_bug!(sp, "expected value, found {:?}", defn);
+            }
         }
     }
-}
 
-// Instantiates the given path, which must refer to an item with the given
-// number of type parameters and type.
-pub fn instantiate_path(&self,
-                        segments: &[hir::PathSegment],
-                        type_scheme: TypeScheme<'tcx>,
-                        type_predicates: &ty::GenericPredicates<'tcx>,
-                        opt_self_ty: Option<Ty<'tcx>>,
-                        def: Def,
-                        span: Span,
-                        node_id: ast::NodeId) {
-    debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
-           segments,
-           def,
-           node_id,
-           type_scheme);
+    // Instantiates the given path, which must refer to an item with the given
+    // number of type parameters and type.
+    pub fn instantiate_path(&self,
+                            segments: &[hir::PathSegment],
+                            type_scheme: TypeScheme<'tcx>,
+                            type_predicates: &ty::GenericPredicates<'tcx>,
+                            opt_self_ty: Option<Ty<'tcx>>,
+                            def: Def,
+                            span: Span,
+                            node_id: ast::NodeId) {
+        debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
+               segments,
+               def,
+               node_id,
+               type_scheme);
 
-    // We need to extract the type parameters supplied by the user in
-    // the path `path`. Due to the current setup, this is a bit of a
-    // tricky-process; the problem is that resolve only tells us the
-    // end-point of the path resolution, and not the intermediate steps.
-    // Luckily, we can (at least for now) deduce the intermediate steps
-    // just from the end-point.
-    //
-    // There are basically four cases to consider:
-    //
-    // 1. Reference to a *type*, such as a struct or enum:
-    //
-    //        mod a { struct Foo<T> { ... } }
-    //
-    //    Because we don't allow types to be declared within one
-    //    another, a path that leads to a type will always look like
-    //    `a::b::Foo<T>` where `a` and `b` are modules. This implies
-    //    that only the final segment can have type parameters, and
-    //    they are located in the TypeSpace.
-    //
-    //    *Note:* Generally speaking, references to types don't
-    //    actually pass through this function, but rather the
-    //    `ast_ty_to_ty` function in `astconv`. However, in the case
-    //    of struct patterns (and maybe literals) we do invoke
-    //    `instantiate_path` to get the general type of an instance of
-    //    a struct. (In these cases, there are actually no type
-    //    parameters permitted at present, but perhaps we will allow
-    //    them in the future.)
-    //
-    // 1b. Reference to an enum variant or tuple-like struct:
-    //
-    //        struct foo<T>(...)
-    //        enum E<T> { foo(...) }
-    //
-    //    In these cases, the parameters are declared in the type
-    //    space.
-    //
-    // 2. Reference to a *fn item*:
-    //
-    //        fn foo<T>() { }
-    //
-    //    In this case, the path will again always have the form
-    //    `a::b::foo::<T>` where only the final segment should have
-    //    type parameters. However, in this case, those parameters are
-    //    declared on a value, and hence are in the `FnSpace`.
-    //
-    // 3. Reference to a *method*:
-    //
-    //        impl<A> SomeStruct<A> {
-    //            fn foo<B>(...)
-    //        }
-    //
-    //    Here we can have a path like
-    //    `a::b::SomeStruct::<A>::foo::<B>`, in which case parameters
-    //    may appear in two places. The penultimate segment,
-    //    `SomeStruct::<A>`, contains parameters in TypeSpace, and the
-    //    final segment, `foo::<B>` contains parameters in fn space.
-    //
-    // 4. Reference to an *associated const*:
-    //
-    // impl<A> AnotherStruct<A> {
-    // const FOO: B = BAR;
-    // }
-    //
-    // The path in this case will look like
-    // `a::b::AnotherStruct::<A>::FOO`, so the penultimate segment
-    // only will have parameters in TypeSpace.
-    //
-    // The first step then is to categorize the segments appropriately.
+        // We need to extract the type parameters supplied by the user in
+        // the path `path`. Due to the current setup, this is a bit of a
+        // tricky-process; the problem is that resolve only tells us the
+        // end-point of the path resolution, and not the intermediate steps.
+        // Luckily, we can (at least for now) deduce the intermediate steps
+        // just from the end-point.
+        //
+        // There are basically four cases to consider:
+        //
+        // 1. Reference to a *type*, such as a struct or enum:
+        //
+        //        mod a { struct Foo<T> { ... } }
+        //
+        //    Because we don't allow types to be declared within one
+        //    another, a path that leads to a type will always look like
+        //    `a::b::Foo<T>` where `a` and `b` are modules. This implies
+        //    that only the final segment can have type parameters, and
+        //    they are located in the TypeSpace.
+        //
+        //    *Note:* Generally speaking, references to types don't
+        //    actually pass through this function, but rather the
+        //    `ast_ty_to_ty` function in `astconv`. However, in the case
+        //    of struct patterns (and maybe literals) we do invoke
+        //    `instantiate_path` to get the general type of an instance of
+        //    a struct. (In these cases, there are actually no type
+        //    parameters permitted at present, but perhaps we will allow
+        //    them in the future.)
+        //
+        // 1b. Reference to an enum variant or tuple-like struct:
+        //
+        //        struct foo<T>(...)
+        //        enum E<T> { foo(...) }
+        //
+        //    In these cases, the parameters are declared in the type
+        //    space.
+        //
+        // 2. Reference to a *fn item*:
+        //
+        //        fn foo<T>() { }
+        //
+        //    In this case, the path will again always have the form
+        //    `a::b::foo::<T>` where only the final segment should have
+        //    type parameters. However, in this case, those parameters are
+        //    declared on a value, and hence are in the `FnSpace`.
+        //
+        // 3. Reference to a *method*:
+        //
+        //        impl<A> SomeStruct<A> {
+        //            fn foo<B>(...)
+        //        }
+        //
+        //    Here we can have a path like
+        //    `a::b::SomeStruct::<A>::foo::<B>`, in which case parameters
+        //    may appear in two places. The penultimate segment,
+        //    `SomeStruct::<A>`, contains parameters in TypeSpace, and the
+        //    final segment, `foo::<B>` contains parameters in fn space.
+        //
+        // 4. Reference to an *associated const*:
+        //
+        // impl<A> AnotherStruct<A> {
+        // const FOO: B = BAR;
+        // }
+        //
+        // The path in this case will look like
+        // `a::b::AnotherStruct::<A>::FOO`, so the penultimate segment
+        // only will have parameters in TypeSpace.
+        //
+        // The first step then is to categorize the segments appropriately.
 
-    assert!(!segments.is_empty());
+        assert!(!segments.is_empty());
 
-    let mut ufcs_associated = None;
-    let mut segment_spaces: Vec<_>;
-    match def {
-        // Case 1 and 1b. Reference to a *type* or *enum variant*.
-        Def::SelfTy(..) |
-        Def::Struct(..) |
-        Def::Variant(..) |
-        Def::Enum(..) |
-        Def::TyAlias(..) |
-        Def::AssociatedTy(..) |
-        Def::Trait(..) |
-        Def::PrimTy(..) |
-        Def::TyParam(..) => {
-            // Everything but the final segment should have no
-            // parameters at all.
-            segment_spaces = vec![None; segments.len() - 1];
-            segment_spaces.push(Some(subst::TypeSpace));
-        }
-
-        // Case 2. Reference to a top-level value.
-        Def::Fn(..) |
-        Def::Const(..) |
-        Def::Static(..) => {
-            segment_spaces = vec![None; segments.len() - 1];
-            segment_spaces.push(Some(subst::FnSpace));
-        }
-
-        // Case 3. Reference to a method.
-        Def::Method(def_id) => {
-            let container = self.tcx.impl_or_trait_item(def_id).container();
-            match container {
-                ty::TraitContainer(trait_did) => {
-                    callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
-                }
-                ty::ImplContainer(_) => {}
+        let mut ufcs_associated = None;
+        let mut segment_spaces: Vec<_>;
+        match def {
+            // Case 1 and 1b. Reference to a *type* or *enum variant*.
+            Def::SelfTy(..) |
+            Def::Struct(..) |
+            Def::Variant(..) |
+            Def::Enum(..) |
+            Def::TyAlias(..) |
+            Def::AssociatedTy(..) |
+            Def::Trait(..) |
+            Def::PrimTy(..) |
+            Def::TyParam(..) => {
+                // Everything but the final segment should have no
+                // parameters at all.
+                segment_spaces = vec![None; segments.len() - 1];
+                segment_spaces.push(Some(subst::TypeSpace));
             }
 
-            if segments.len() >= 2 {
-                segment_spaces = vec![None; segments.len() - 2];
-                segment_spaces.push(Some(subst::TypeSpace));
+            // Case 2. Reference to a top-level value.
+            Def::Fn(..) |
+            Def::Const(..) |
+            Def::Static(..) => {
+                segment_spaces = vec![None; segments.len() - 1];
                 segment_spaces.push(Some(subst::FnSpace));
-            } else {
-                // `<T>::method` will end up here, and so can `T::method`.
-                let self_ty = opt_self_ty.expect("UFCS sugared method missing Self");
-                segment_spaces = vec![Some(subst::FnSpace)];
-                ufcs_associated = Some((container, self_ty));
             }
-        }
 
-        Def::AssociatedConst(def_id) => {
-            let container = self.tcx.impl_or_trait_item(def_id).container();
-            match container {
-                ty::TraitContainer(trait_did) => {
-                    callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
+            // Case 3. Reference to a method.
+            Def::Method(def_id) => {
+                let container = self.tcx.impl_or_trait_item(def_id).container();
+                match container {
+                    ty::TraitContainer(trait_did) => {
+                        callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
+                    }
+                    ty::ImplContainer(_) => {}
+                }
+
+                if segments.len() >= 2 {
+                    segment_spaces = vec![None; segments.len() - 2];
+                    segment_spaces.push(Some(subst::TypeSpace));
+                    segment_spaces.push(Some(subst::FnSpace));
+                } else {
+                    // `<T>::method` will end up here, and so can `T::method`.
+                    let self_ty = opt_self_ty.expect("UFCS sugared method missing Self");
+                    segment_spaces = vec![Some(subst::FnSpace)];
+                    ufcs_associated = Some((container, self_ty));
                 }
-                ty::ImplContainer(_) => {}
             }
 
-            if segments.len() >= 2 {
-                segment_spaces = vec![None; segments.len() - 2];
-                segment_spaces.push(Some(subst::TypeSpace));
-                segment_spaces.push(None);
+            Def::AssociatedConst(def_id) => {
+                let container = self.tcx.impl_or_trait_item(def_id).container();
+                match container {
+                    ty::TraitContainer(trait_did) => {
+                        callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
+                    }
+                    ty::ImplContainer(_) => {}
+                }
+
+                if segments.len() >= 2 {
+                    segment_spaces = vec![None; segments.len() - 2];
+                    segment_spaces.push(Some(subst::TypeSpace));
+                    segment_spaces.push(None);
+                } else {
+                    // `<T>::CONST` will end up here, and so can `T::CONST`.
+                    let self_ty = opt_self_ty.expect("UFCS sugared const missing Self");
+                    segment_spaces = vec![None];
+                    ufcs_associated = Some((container, self_ty));
+                }
+            }
+
+            // Other cases. Various nonsense that really shouldn't show up
+            // here. If they do, an error will have been reported
+            // elsewhere. (I hope)
+            Def::Mod(..) |
+            Def::ForeignMod(..) |
+            Def::Local(..) |
+            Def::Label(..) |
+            Def::Upvar(..) => {
+                segment_spaces = vec![None; segments.len()];
+            }
+
+            Def::Err => {
+                self.set_tainted_by_errors();
+                segment_spaces = vec![None; segments.len()];
+            }
+        }
+        assert_eq!(segment_spaces.len(), segments.len());
+
+        // In `<T as Trait<A, B>>::method`, `A` and `B` are mandatory, but
+        // `opt_self_ty` can also be Some for `Foo::method`, where Foo's
+        // type parameters are not mandatory.
+        let require_type_space = opt_self_ty.is_some() && ufcs_associated.is_none();
+
+        debug!("segment_spaces={:?}", segment_spaces);
+
+        // Next, examine the definition, and determine how many type
+        // parameters we expect from each space.
+        let type_defs = &type_scheme.generics.types;
+        let region_defs = &type_scheme.generics.regions;
+
+        // Now that we have categorized what space the parameters for each
+        // segment belong to, let's sort out the parameters that the user
+        // provided (if any) into their appropriate spaces. We'll also report
+        // errors if type parameters are provided in an inappropriate place.
+        let mut substs = Substs::empty();
+        for (&opt_space, segment) in segment_spaces.iter().zip(segments) {
+            if let Some(space) = opt_space {
+                self.push_explicit_parameters_from_segment_to_substs(space,
+                                                                     span,
+                                                                     type_defs,
+                                                                     region_defs,
+                                                                     segment,
+                                                                     &mut substs);
             } else {
-                // `<T>::CONST` will end up here, and so can `T::CONST`.
-                let self_ty = opt_self_ty.expect("UFCS sugared const missing Self");
-                segment_spaces = vec![None];
-                ufcs_associated = Some((container, self_ty));
+                self.tcx.prohibit_type_params(slice::ref_slice(segment));
+            }
+        }
+        if let Some(self_ty) = opt_self_ty {
+            if type_defs.len(subst::SelfSpace) == 1 {
+                substs.types.push(subst::SelfSpace, self_ty);
             }
         }
 
-        // Other cases. Various nonsense that really shouldn't show up
-        // here. If they do, an error will have been reported
-        // elsewhere. (I hope)
-        Def::Mod(..) |
-        Def::ForeignMod(..) |
-        Def::Local(..) |
-        Def::Label(..) |
-        Def::Upvar(..) => {
-            segment_spaces = vec![None; segments.len()];
+        // Now we have to compare the types that the user *actually*
+        // provided against the types that were *expected*. If the user
+        // did not provide any types, then we want to substitute inference
+        // variables. If the user provided some types, we may still need
+        // to add defaults. If the user provided *too many* types, that's
+        // a problem.
+        for &space in &[subst::SelfSpace, subst::TypeSpace, subst::FnSpace] {
+            self.adjust_type_parameters(span, space, type_defs,
+                                        require_type_space, &mut substs);
+            assert_eq!(substs.types.len(space), type_defs.len(space));
+
+            self.adjust_region_parameters(span, space, region_defs, &mut substs);
+            assert_eq!(substs.regions.len(space), region_defs.len(space));
         }
 
-        Def::Err => {
-            self.set_tainted_by_errors();
-            segment_spaces = vec![None; segments.len()];
-        }
-    }
-    assert_eq!(segment_spaces.len(), segments.len());
+        // The things we are substituting into the type should not contain
+        // escaping late-bound regions, and nor should the base type scheme.
+        let substs = self.tcx.mk_substs(substs);
+        assert!(!substs.has_regions_escaping_depth(0));
+        assert!(!type_scheme.has_escaping_regions());
 
-    // In `<T as Trait<A, B>>::method`, `A` and `B` are mandatory, but
-    // `opt_self_ty` can also be Some for `Foo::method`, where Foo's
-    // type parameters are not mandatory.
-    let require_type_space = opt_self_ty.is_some() && ufcs_associated.is_none();
+        // Add all the obligations that are required, substituting and
+        // normalized appropriately.
+        let bounds = self.instantiate_bounds(span, &substs, &type_predicates);
+        self.add_obligations_for_parameters(
+            traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())),
+            &bounds);
 
-    debug!("segment_spaces={:?}", segment_spaces);
-
-    // Next, examine the definition, and determine how many type
-    // parameters we expect from each space.
-    let type_defs = &type_scheme.generics.types;
-    let region_defs = &type_scheme.generics.regions;
-
-    // Now that we have categorized what space the parameters for each
-    // segment belong to, let's sort out the parameters that the user
-    // provided (if any) into their appropriate spaces. We'll also report
-    // errors if type parameters are provided in an inappropriate place.
-    let mut substs = Substs::empty();
-    for (&opt_space, segment) in segment_spaces.iter().zip(segments) {
-        if let Some(space) = opt_space {
-            self.push_explicit_parameters_from_segment_to_substs(space,
-                                                                 span,
-                                                                 type_defs,
-                                                                 region_defs,
-                                                                 segment,
-                                                                 &mut substs);
-        } else {
-            self.tcx.prohibit_type_params(slice::ref_slice(segment));
-        }
-    }
-    if let Some(self_ty) = opt_self_ty {
-        if type_defs.len(subst::SelfSpace) == 1 {
-            substs.types.push(subst::SelfSpace, self_ty);
-        }
-    }
-
-    // Now we have to compare the types that the user *actually*
-    // provided against the types that were *expected*. If the user
-    // did not provide any types, then we want to substitute inference
-    // variables. If the user provided some types, we may still need
-    // to add defaults. If the user provided *too many* types, that's
-    // a problem.
-    for &space in &[subst::SelfSpace, subst::TypeSpace, subst::FnSpace] {
-        self.adjust_type_parameters(span, space, type_defs,
-                                    require_type_space, &mut substs);
-        assert_eq!(substs.types.len(space), type_defs.len(space));
-
-        self.adjust_region_parameters(span, space, region_defs, &mut substs);
-        assert_eq!(substs.regions.len(space), region_defs.len(space));
-    }
-
-    // The things we are substituting into the type should not contain
-    // escaping late-bound regions, and nor should the base type scheme.
-    let substs = self.tcx.mk_substs(substs);
-    assert!(!substs.has_regions_escaping_depth(0));
-    assert!(!type_scheme.has_escaping_regions());
-
-    // Add all the obligations that are required, substituting and
-    // normalized appropriately.
-    let bounds = self.instantiate_bounds(span, &substs, &type_predicates);
-    self.add_obligations_for_parameters(
-        traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())),
-        &bounds);
-
-    // Substitute the values for the type parameters into the type of
-    // the referenced item.
-    let ty_substituted = self.instantiate_type_scheme(span, &substs, &type_scheme.ty);
+        // Substitute the values for the type parameters into the type of
+        // the referenced item.
+        let ty_substituted = self.instantiate_type_scheme(span, &substs, &type_scheme.ty);
 
 
-    if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated {
-        // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
-        // is inherent, there is no `Self` parameter, instead, the impl needs
-        // type parameters, which we can infer by unifying the provided `Self`
-        // with the substituted impl type.
-        let impl_scheme = self.tcx.lookup_item_type(impl_def_id);
-        assert_eq!(substs.types.len(subst::TypeSpace),
-                   impl_scheme.generics.types.len(subst::TypeSpace));
-        assert_eq!(substs.regions.len(subst::TypeSpace),
-                   impl_scheme.generics.regions.len(subst::TypeSpace));
+        if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated {
+            // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
+            // is inherent, there is no `Self` parameter, instead, the impl needs
+            // type parameters, which we can infer by unifying the provided `Self`
+            // with the substituted impl type.
+            let impl_scheme = self.tcx.lookup_item_type(impl_def_id);
+            assert_eq!(substs.types.len(subst::TypeSpace),
+                       impl_scheme.generics.types.len(subst::TypeSpace));
+            assert_eq!(substs.regions.len(subst::TypeSpace),
+                       impl_scheme.generics.regions.len(subst::TypeSpace));
 
-        let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty);
-        match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) {
-            Ok(InferOk { obligations, .. }) => {
-                // FIXME(#32730) propagate obligations
-                assert!(obligations.is_empty());
-            }
-            Err(_) => {
-                span_bug!(span,
-                    "instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
-                    self_ty,
-                    impl_ty);
+            let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty);
+            match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) {
+                Ok(InferOk { obligations, .. }) => {
+                    // FIXME(#32730) propagate obligations
+                    assert!(obligations.is_empty());
+                }
+                Err(_) => {
+                    span_bug!(span,
+                        "instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
+                        self_ty,
+                        impl_ty);
+                }
             }
         }
-    }
 
-    debug!("instantiate_path: type of {:?} is {:?}",
-           node_id,
-           ty_substituted);
-    self.write_ty(node_id, ty_substituted);
-    self.write_substs(node_id, ty::ItemSubsts {
-        substs: substs
-    });
-}
+        debug!("instantiate_path: type of {:?} is {:?}",
+               node_id,
+               ty_substituted);
+        self.write_ty(node_id, ty_substituted);
+        self.write_substs(node_id, ty::ItemSubsts {
+            substs: substs
+        });
+    }
 
     /// Finds the parameters that the user provided and adds them to `substs`. If too many
     /// parameters are provided, then reports an error and clears the output vector.
@@ -4628,40 +4634,40 @@ pub fn instantiate_path(&self,
             self.region_vars_for_defs(span, desired));
     }
 
-fn structurally_resolve_type_or_else<F>(&self, sp: Span, ty: Ty<'tcx>, f: F)
-                                        -> Ty<'tcx>
-    where F: Fn() -> Ty<'tcx>
-{
-    let mut ty = self.resolve_type_vars_with_obligations(ty);
+    fn structurally_resolve_type_or_else<F>(&self, sp: Span, ty: Ty<'tcx>, f: F)
+                                            -> Ty<'tcx>
+        where F: Fn() -> Ty<'tcx>
+    {
+        let mut ty = self.resolve_type_vars_with_obligations(ty);
 
-    if ty.is_ty_var() {
-        let alternative = f();
+        if ty.is_ty_var() {
+            let alternative = f();
 
-        // If not, error.
-        if alternative.is_ty_var() || alternative.references_error() {
-            if !self.is_tainted_by_errors() {
-                self.type_error_message(sp, |_actual| {
-                    "the type of this value must be known in this context".to_string()
-                }, ty, None);
+            // If not, error.
+            if alternative.is_ty_var() || alternative.references_error() {
+                if !self.is_tainted_by_errors() {
+                    self.type_error_message(sp, |_actual| {
+                        "the type of this value must be known in this context".to_string()
+                    }, ty, None);
+                }
+                self.demand_suptype(sp, self.tcx.types.err, ty);
+                ty = self.tcx.types.err;
+            } else {
+                self.demand_suptype(sp, alternative, ty);
+                ty = alternative;
             }
-            self.demand_suptype(sp, self.tcx.types.err, ty);
-            ty = self.tcx.types.err;
-        } else {
-            self.demand_suptype(sp, alternative, ty);
-            ty = alternative;
         }
+
+        ty
     }
 
-    ty
-}
-
-// Resolves `typ` by a single level if `typ` is a type variable.  If no
-// resolution is possible, then an error is reported.
-pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-    self.structurally_resolve_type_or_else(sp, ty, || {
-        self.tcx.types.err
-    })
-}
+    // Resolves `typ` by a single level if `typ` is a type variable.  If no
+    // resolution is possible, then an error is reported.
+    pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.structurally_resolve_type_or_else(sp, ty, || {
+            self.tcx.types.err
+        })
+    }
 }
 
 // Returns true if b contains a break that can exit from b
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 3986b866033..8604dadf46d 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -18,330 +18,335 @@ use syntax::parse::token;
 use rustc::hir;
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-/// Check a `a <op>= b`
-pub fn check_binop_assign(&self,
-                          expr: &'gcx hir::Expr,
-                          op: hir::BinOp,
-                          lhs_expr: &'gcx hir::Expr,
-                          rhs_expr: &'gcx hir::Expr)
-{
-    self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
+    /// Check a `a <op>= b`
+    pub fn check_binop_assign(&self,
+                              expr: &'gcx hir::Expr,
+                              op: hir::BinOp,
+                              lhs_expr: &'gcx hir::Expr,
+                              rhs_expr: &'gcx hir::Expr)
+    {
+        self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
 
-    let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
-    let (rhs_ty, return_ty) =
-        self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
-    let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
-
-    if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
-        self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
-        self.write_nil(expr.id);
-    } else {
-        self.write_ty(expr.id, return_ty);
-    }
-
-    let tcx = self.tcx;
-    if !tcx.expr_is_lval(lhs_expr) {
-        span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression");
-    }
-}
-
-/// Check a potentially overloaded binary operator.
-pub fn check_binop(&self,
-                   expr: &'gcx hir::Expr,
-                   op: hir::BinOp,
-                   lhs_expr: &'gcx hir::Expr,
-                   rhs_expr: &'gcx hir::Expr)
-{
-    let tcx = self.tcx;
-
-    debug!("check_binop(expr.id={}, expr={:?}, op={:?}, lhs_expr={:?}, rhs_expr={:?})",
-           expr.id,
-           expr,
-           op,
-           lhs_expr,
-           rhs_expr);
-
-    self.check_expr(lhs_expr);
-    let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
-
-    match BinOpCategory::from(op) {
-        BinOpCategory::Shortcircuit => {
-            // && and || are a simple case.
-            self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
-            self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool());
-            self.write_ty(expr.id, tcx.mk_bool());
-        }
-        _ => {
-            // Otherwise, we always treat operators as if they are
-            // overloaded. This is the way to be most flexible w/r/t
-            // types that get inferred.
-            let (rhs_ty, return_ty) =
-                self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::No);
-
-            // Supply type inference hints if relevant. Probably these
-            // hints should be enforced during select as part of the
-            // `consider_unification_despite_ambiguity` routine, but this
-            // more convenient for now.
-            //
-            // The basic idea is to help type inference by taking
-            // advantage of things we know about how the impls for
-            // scalar types are arranged. This is important in a
-            // scenario like `1_u32 << 2`, because it lets us quickly
-            // deduce that the result type should be `u32`, even
-            // though we don't know yet what type 2 has and hence
-            // can't pin this down to a specific impl.
-            let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
-            if
-                !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() &&
-                is_builtin_binop(lhs_ty, rhs_ty, op)
-            {
-                let builtin_return_ty =
-                    self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
-                self.demand_suptype(expr.span, builtin_return_ty, return_ty);
-            }
+        let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
+        let (rhs_ty, return_ty) =
+            self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
+        let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
 
+        if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
+            self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
+            self.write_nil(expr.id);
+        } else {
             self.write_ty(expr.id, return_ty);
         }
-    }
-}
 
-fn enforce_builtin_binop_types(&self,
-                               lhs_expr: &'gcx hir::Expr,
-                               lhs_ty: Ty<'tcx>,
-                               rhs_expr: &'gcx hir::Expr,
-                               rhs_ty: Ty<'tcx>,
-                               op: hir::BinOp)
-                               -> Ty<'tcx>
-{
-    debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op));
-
-    let tcx = self.tcx;
-    match BinOpCategory::from(op) {
-        BinOpCategory::Shortcircuit => {
-            self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
-            self.demand_suptype(rhs_expr.span, tcx.mk_bool(), rhs_ty);
-            tcx.mk_bool()
-        }
-
-        BinOpCategory::Shift => {
-            // result type is same as LHS always
-            lhs_ty
-        }
-
-        BinOpCategory::Math |
-        BinOpCategory::Bitwise => {
-            // both LHS and RHS and result will have the same type
-            self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty);
-            lhs_ty
-        }
-
-        BinOpCategory::Comparison => {
-            // both LHS and RHS and result will have the same type
-            self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty);
-            tcx.mk_bool()
+        let tcx = self.tcx;
+        if !tcx.expr_is_lval(lhs_expr) {
+            span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression");
         }
     }
-}
 
-fn check_overloaded_binop(&self,
-                          expr: &'gcx hir::Expr,
-                          lhs_expr: &'gcx hir::Expr,
-                          lhs_ty: Ty<'tcx>,
-                          rhs_expr: &'gcx hir::Expr,
-                          op: hir::BinOp,
-                          is_assign: IsAssign)
-                          -> (Ty<'tcx>, Ty<'tcx>)
-{
-    debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?})",
-           expr.id,
-           lhs_ty,
-           is_assign);
+    /// Check a potentially overloaded binary operator.
+    pub fn check_binop(&self,
+                       expr: &'gcx hir::Expr,
+                       op: hir::BinOp,
+                       lhs_expr: &'gcx hir::Expr,
+                       rhs_expr: &'gcx hir::Expr)
+    {
+        let tcx = self.tcx;
 
-    let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign);
+        debug!("check_binop(expr.id={}, expr={:?}, op={:?}, lhs_expr={:?}, rhs_expr={:?})",
+               expr.id,
+               expr,
+               op,
+               lhs_expr,
+               rhs_expr);
 
-    // NB: As we have not yet type-checked the RHS, we don't have the
-    // type at hand. Make a variable to represent it. The whole reason
-    // for this indirection is so that, below, we can check the expr
-    // using this variable as the expected type, which sometimes lets
-    // us do better coercions than we would be able to do otherwise,
-    // particularly for things like `String + &String`.
-    let rhs_ty_var = self.next_ty_var();
+        self.check_expr(lhs_expr);
+        let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
 
-    let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var],
-                                                token::intern(name), trait_def_id,
-                                                lhs_expr) {
-        Ok(return_ty) => return_ty,
-        Err(()) => {
-            // error types are considered "builtin"
-            if !lhs_ty.references_error() {
-                if let IsAssign::Yes = is_assign {
-                    span_err!(self.tcx.sess, lhs_expr.span, E0368,
-                              "binary assignment operation `{}=` cannot be applied to type `{}`",
-                              op.node.as_str(),
-                              lhs_ty);
-                } else {
-                    let mut err = struct_span_err!(self.tcx.sess, lhs_expr.span, E0369,
-                        "binary operation `{}` cannot be applied to type `{}`",
-                        op.node.as_str(),
-                        lhs_ty);
-                    let missing_trait = match op.node {
-                        hir::BiAdd    => Some("std::ops::Add"),
-                        hir::BiSub    => Some("std::ops::Sub"),
-                        hir::BiMul    => Some("std::ops::Mul"),
-                        hir::BiDiv    => Some("std::ops::Div"),
-                        hir::BiRem    => Some("std::ops::Rem"),
-                        hir::BiBitAnd => Some("std::ops::BitAnd"),
-                        hir::BiBitOr  => Some("std::ops::BitOr"),
-                        hir::BiShl    => Some("std::ops::Shl"),
-                        hir::BiShr    => Some("std::ops::Shr"),
-                        hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
-                        hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
-                            Some("std::cmp::PartialOrd"),
-                        _             => None
-                    };
+        match BinOpCategory::from(op) {
+            BinOpCategory::Shortcircuit => {
+                // && and || are a simple case.
+                self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
+                self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool());
+                self.write_ty(expr.id, tcx.mk_bool());
+            }
+            _ => {
+                // Otherwise, we always treat operators as if they are
+                // overloaded. This is the way to be most flexible w/r/t
+                // types that get inferred.
+                let (rhs_ty, return_ty) =
+                    self.check_overloaded_binop(expr, lhs_expr, lhs_ty,
+                                                rhs_expr, op, IsAssign::No);
 
-                    if let Some(missing_trait) = missing_trait {
-                        span_note!(&mut err, lhs_expr.span,
-                                   "an implementation of `{}` might be missing for `{}`",
-                                    missing_trait, lhs_ty);
+                // Supply type inference hints if relevant. Probably these
+                // hints should be enforced during select as part of the
+                // `consider_unification_despite_ambiguity` routine, but this
+                // more convenient for now.
+                //
+                // The basic idea is to help type inference by taking
+                // advantage of things we know about how the impls for
+                // scalar types are arranged. This is important in a
+                // scenario like `1_u32 << 2`, because it lets us quickly
+                // deduce that the result type should be `u32`, even
+                // though we don't know yet what type 2 has and hence
+                // can't pin this down to a specific impl.
+                let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
+                if
+                    !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() &&
+                    is_builtin_binop(lhs_ty, rhs_ty, op)
+                {
+                    let builtin_return_ty =
+                        self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
+                    self.demand_suptype(expr.span, builtin_return_ty, return_ty);
+                }
+
+                self.write_ty(expr.id, return_ty);
+            }
+        }
+    }
+
+    fn enforce_builtin_binop_types(&self,
+                                   lhs_expr: &'gcx hir::Expr,
+                                   lhs_ty: Ty<'tcx>,
+                                   rhs_expr: &'gcx hir::Expr,
+                                   rhs_ty: Ty<'tcx>,
+                                   op: hir::BinOp)
+                                   -> Ty<'tcx>
+    {
+        debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op));
+
+        let tcx = self.tcx;
+        match BinOpCategory::from(op) {
+            BinOpCategory::Shortcircuit => {
+                self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
+                self.demand_suptype(rhs_expr.span, tcx.mk_bool(), rhs_ty);
+                tcx.mk_bool()
+            }
+
+            BinOpCategory::Shift => {
+                // result type is same as LHS always
+                lhs_ty
+            }
+
+            BinOpCategory::Math |
+            BinOpCategory::Bitwise => {
+                // both LHS and RHS and result will have the same type
+                self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty);
+                lhs_ty
+            }
+
+            BinOpCategory::Comparison => {
+                // both LHS and RHS and result will have the same type
+                self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty);
+                tcx.mk_bool()
+            }
+        }
+    }
+
+    fn check_overloaded_binop(&self,
+                              expr: &'gcx hir::Expr,
+                              lhs_expr: &'gcx hir::Expr,
+                              lhs_ty: Ty<'tcx>,
+                              rhs_expr: &'gcx hir::Expr,
+                              op: hir::BinOp,
+                              is_assign: IsAssign)
+                              -> (Ty<'tcx>, Ty<'tcx>)
+    {
+        debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?})",
+               expr.id,
+               lhs_ty,
+               is_assign);
+
+        let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign);
+
+        // NB: As we have not yet type-checked the RHS, we don't have the
+        // type at hand. Make a variable to represent it. The whole reason
+        // for this indirection is so that, below, we can check the expr
+        // using this variable as the expected type, which sometimes lets
+        // us do better coercions than we would be able to do otherwise,
+        // particularly for things like `String + &String`.
+        let rhs_ty_var = self.next_ty_var();
+
+        let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var],
+                                                    token::intern(name), trait_def_id,
+                                                    lhs_expr) {
+            Ok(return_ty) => return_ty,
+            Err(()) => {
+                // error types are considered "builtin"
+                if !lhs_ty.references_error() {
+                    if let IsAssign::Yes = is_assign {
+                        span_err!(self.tcx.sess, lhs_expr.span, E0368,
+                                  "binary assignment operation `{}=` \
+                                   cannot be applied to type `{}`",
+                                  op.node.as_str(),
+                                  lhs_ty);
+                    } else {
+                        let mut err = struct_span_err!(self.tcx.sess, lhs_expr.span, E0369,
+                            "binary operation `{}` cannot be applied to type `{}`",
+                            op.node.as_str(),
+                            lhs_ty);
+                        let missing_trait = match op.node {
+                            hir::BiAdd    => Some("std::ops::Add"),
+                            hir::BiSub    => Some("std::ops::Sub"),
+                            hir::BiMul    => Some("std::ops::Mul"),
+                            hir::BiDiv    => Some("std::ops::Div"),
+                            hir::BiRem    => Some("std::ops::Rem"),
+                            hir::BiBitAnd => Some("std::ops::BitAnd"),
+                            hir::BiBitOr  => Some("std::ops::BitOr"),
+                            hir::BiShl    => Some("std::ops::Shl"),
+                            hir::BiShr    => Some("std::ops::Shr"),
+                            hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
+                            hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
+                                Some("std::cmp::PartialOrd"),
+                            _             => None
+                        };
+
+                        if let Some(missing_trait) = missing_trait {
+                            span_note!(&mut err, lhs_expr.span,
+                                       "an implementation of `{}` might be missing for `{}`",
+                                        missing_trait, lhs_ty);
+                        }
+                        err.emit();
                     }
-                    err.emit();
+                }
+                self.tcx.types.err
+            }
+        };
+
+        // see `NB` above
+        self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
+
+        (rhs_ty_var, return_ty)
+    }
+
+    pub fn check_user_unop(&self,
+                           op_str: &str,
+                           mname: &str,
+                           trait_did: Option<DefId>,
+                           ex: &'gcx hir::Expr,
+                           operand_expr: &'gcx hir::Expr,
+                           operand_ty: Ty<'tcx>,
+                           op: hir::UnOp)
+                           -> Ty<'tcx>
+    {
+        assert!(op.is_by_value());
+        match self.lookup_op_method(ex, operand_ty, vec![],
+                                    token::intern(mname), trait_did,
+                                    operand_expr) {
+            Ok(t) => t,
+            Err(()) => {
+                self.type_error_message(ex.span, |actual| {
+                    format!("cannot apply unary operator `{}` to type `{}`",
+                            op_str, actual)
+                }, operand_ty, None);
+                self.tcx.types.err
+            }
+        }
+    }
+
+    fn name_and_trait_def_id(&self,
+                             op: hir::BinOp,
+                             is_assign: IsAssign)
+                             -> (&'static str, Option<DefId>) {
+        let lang = &self.tcx.lang_items;
+
+        if let IsAssign::Yes = is_assign {
+            match op.node {
+                hir::BiAdd => ("add_assign", lang.add_assign_trait()),
+                hir::BiSub => ("sub_assign", lang.sub_assign_trait()),
+                hir::BiMul => ("mul_assign", lang.mul_assign_trait()),
+                hir::BiDiv => ("div_assign", lang.div_assign_trait()),
+                hir::BiRem => ("rem_assign", lang.rem_assign_trait()),
+                hir::BiBitXor => ("bitxor_assign", lang.bitxor_assign_trait()),
+                hir::BiBitAnd => ("bitand_assign", lang.bitand_assign_trait()),
+                hir::BiBitOr => ("bitor_assign", lang.bitor_assign_trait()),
+                hir::BiShl => ("shl_assign", lang.shl_assign_trait()),
+                hir::BiShr => ("shr_assign", lang.shr_assign_trait()),
+                hir::BiLt | hir::BiLe |
+                hir::BiGe | hir::BiGt |
+                hir::BiEq | hir::BiNe |
+                hir::BiAnd | hir::BiOr => {
+                    span_bug!(op.span,
+                              "impossible assignment operation: {}=",
+                              op.node.as_str())
                 }
             }
-            self.tcx.types.err
-        }
-    };
-
-    // see `NB` above
-    self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
-
-    (rhs_ty_var, return_ty)
-}
-
-pub fn check_user_unop(&self,
-                       op_str: &str,
-                       mname: &str,
-                       trait_did: Option<DefId>,
-                       ex: &'gcx hir::Expr,
-                       operand_expr: &'gcx hir::Expr,
-                       operand_ty: Ty<'tcx>,
-                       op: hir::UnOp)
-                       -> Ty<'tcx>
-{
-    assert!(op.is_by_value());
-    match self.lookup_op_method(ex, operand_ty, vec![],
-                                token::intern(mname), trait_did,
-                                operand_expr) {
-        Ok(t) => t,
-        Err(()) => {
-            self.type_error_message(ex.span, |actual| {
-                format!("cannot apply unary operator `{}` to type `{}`",
-                        op_str, actual)
-            }, operand_ty, None);
-            self.tcx.types.err
-        }
-    }
-}
-
-fn name_and_trait_def_id(&self,
-                         op: hir::BinOp,
-                         is_assign: IsAssign)
-                         -> (&'static str, Option<DefId>) {
-    let lang = &self.tcx.lang_items;
-
-    if let IsAssign::Yes = is_assign {
-        match op.node {
-            hir::BiAdd => ("add_assign", lang.add_assign_trait()),
-            hir::BiSub => ("sub_assign", lang.sub_assign_trait()),
-            hir::BiMul => ("mul_assign", lang.mul_assign_trait()),
-            hir::BiDiv => ("div_assign", lang.div_assign_trait()),
-            hir::BiRem => ("rem_assign", lang.rem_assign_trait()),
-            hir::BiBitXor => ("bitxor_assign", lang.bitxor_assign_trait()),
-            hir::BiBitAnd => ("bitand_assign", lang.bitand_assign_trait()),
-            hir::BiBitOr => ("bitor_assign", lang.bitor_assign_trait()),
-            hir::BiShl => ("shl_assign", lang.shl_assign_trait()),
-            hir::BiShr => ("shr_assign", lang.shr_assign_trait()),
-            hir::BiLt | hir::BiLe | hir::BiGe | hir::BiGt | hir::BiEq | hir::BiNe | hir::BiAnd |
-            hir::BiOr => {
-                span_bug!(op.span,
-                          "impossible assignment operation: {}=",
-                          op.node.as_str())
-            }
-        }
-    } else {
-        match op.node {
-            hir::BiAdd => ("add", lang.add_trait()),
-            hir::BiSub => ("sub", lang.sub_trait()),
-            hir::BiMul => ("mul", lang.mul_trait()),
-            hir::BiDiv => ("div", lang.div_trait()),
-            hir::BiRem => ("rem", lang.rem_trait()),
-            hir::BiBitXor => ("bitxor", lang.bitxor_trait()),
-            hir::BiBitAnd => ("bitand", lang.bitand_trait()),
-            hir::BiBitOr => ("bitor", lang.bitor_trait()),
-            hir::BiShl => ("shl", lang.shl_trait()),
-            hir::BiShr => ("shr", lang.shr_trait()),
-            hir::BiLt => ("lt", lang.ord_trait()),
-            hir::BiLe => ("le", lang.ord_trait()),
-            hir::BiGe => ("ge", lang.ord_trait()),
-            hir::BiGt => ("gt", lang.ord_trait()),
-            hir::BiEq => ("eq", lang.eq_trait()),
-            hir::BiNe => ("ne", lang.eq_trait()),
-            hir::BiAnd | hir::BiOr => {
-                span_bug!(op.span, "&& and || are not overloadable")
+        } else {
+            match op.node {
+                hir::BiAdd => ("add", lang.add_trait()),
+                hir::BiSub => ("sub", lang.sub_trait()),
+                hir::BiMul => ("mul", lang.mul_trait()),
+                hir::BiDiv => ("div", lang.div_trait()),
+                hir::BiRem => ("rem", lang.rem_trait()),
+                hir::BiBitXor => ("bitxor", lang.bitxor_trait()),
+                hir::BiBitAnd => ("bitand", lang.bitand_trait()),
+                hir::BiBitOr => ("bitor", lang.bitor_trait()),
+                hir::BiShl => ("shl", lang.shl_trait()),
+                hir::BiShr => ("shr", lang.shr_trait()),
+                hir::BiLt => ("lt", lang.ord_trait()),
+                hir::BiLe => ("le", lang.ord_trait()),
+                hir::BiGe => ("ge", lang.ord_trait()),
+                hir::BiGt => ("gt", lang.ord_trait()),
+                hir::BiEq => ("eq", lang.eq_trait()),
+                hir::BiNe => ("ne", lang.eq_trait()),
+                hir::BiAnd | hir::BiOr => {
+                    span_bug!(op.span, "&& and || are not overloadable")
+                }
             }
         }
     }
-}
 
-fn lookup_op_method(&self,
-                    expr: &'gcx hir::Expr,
-                    lhs_ty: Ty<'tcx>,
-                    other_tys: Vec<Ty<'tcx>>,
-                    opname: ast::Name,
-                    trait_did: Option<DefId>,
-                    lhs_expr: &'a hir::Expr)
-                    -> Result<Ty<'tcx>,()>
-{
-    debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, trait_did={:?}, lhs_expr={:?})",
-           expr,
-           lhs_ty,
-           opname,
-           trait_did,
-           lhs_expr);
+    fn lookup_op_method(&self,
+                        expr: &'gcx hir::Expr,
+                        lhs_ty: Ty<'tcx>,
+                        other_tys: Vec<Ty<'tcx>>,
+                        opname: ast::Name,
+                        trait_did: Option<DefId>,
+                        lhs_expr: &'a hir::Expr)
+                        -> Result<Ty<'tcx>,()>
+    {
+        debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, \
+                                 trait_did={:?}, lhs_expr={:?})",
+               expr,
+               lhs_ty,
+               opname,
+               trait_did,
+               lhs_expr);
 
-    let method = match trait_did {
-        Some(trait_did) => {
-            self.lookup_method_in_trait_adjusted(expr.span,
-                                                 Some(lhs_expr),
-                                                 opname,
-                                                 trait_did,
-                                                 0,
-                                                 false,
-                                                 lhs_ty,
-                                                 Some(other_tys))
-        }
-        None => None
-    };
+        let method = match trait_did {
+            Some(trait_did) => {
+                self.lookup_method_in_trait_adjusted(expr.span,
+                                                     Some(lhs_expr),
+                                                     opname,
+                                                     trait_did,
+                                                     0,
+                                                     false,
+                                                     lhs_ty,
+                                                     Some(other_tys))
+            }
+            None => None
+        };
 
-    match method {
-        Some(method) => {
-            let method_ty = method.ty;
+        match method {
+            Some(method) => {
+                let method_ty = method.ty;
 
-            // HACK(eddyb) Fully qualified path to work around a resolve bug.
-            let method_call = ::rustc::ty::MethodCall::expr(expr.id);
-            self.tables.borrow_mut().method_map.insert(method_call, method);
+                // HACK(eddyb) Fully qualified path to work around a resolve bug.
+                let method_call = ::rustc::ty::MethodCall::expr(expr.id);
+                self.tables.borrow_mut().method_map.insert(method_call, method);
 
-            // extract return type for method; all late bound regions
-            // should have been instantiated by now
-            let ret_ty = method_ty.fn_ret();
-            Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap())
-        }
-        None => {
-            Err(())
+                // extract return type for method; all late bound regions
+                // should have been instantiated by now
+                let ret_ty = method_ty.fn_ret();
+                Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap())
+            }
+            None => {
+                Err(())
+            }
         }
     }
 }
-}
 
 // Binary operator categories. These categories summarize the behavior
 // with respect to the builtin operationrs supported.
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 931f77951eb..7b79f2ec9bf 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -114,54 +114,54 @@ macro_rules! ignore_err {
 // PUBLIC ENTRY POINTS
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-pub fn regionck_expr(&self, e: &hir::Expr) {
-    let mut rcx = RegionCtxt::new(self, RepeatingScope(e.id), e.id, Subject(e.id));
-    if self.err_count_since_creation() == 0 {
-        // regionck assumes typeck succeeded
-        rcx.visit_expr(e);
-        rcx.visit_region_obligations(e.id);
-    }
-    rcx.resolve_regions_and_report_errors();
-}
-
-/// Region checking during the WF phase for items. `wf_tys` are the
-/// types from which we should derive implied bounds, if any.
-pub fn regionck_item(&self,
-                     item_id: ast::NodeId,
-                     span: Span,
-                     wf_tys: &[Ty<'tcx>]) {
-    debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys);
-    let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(item_id));
-    rcx.free_region_map.relate_free_regions_from_predicates(
-        &self.parameter_environment.caller_bounds);
-    rcx.relate_free_regions(wf_tys, item_id, span);
-    rcx.visit_region_obligations(item_id);
-    rcx.resolve_regions_and_report_errors();
-}
-
-pub fn regionck_fn(&self,
-                   fn_id: ast::NodeId,
-                   fn_span: Span,
-                   decl: &hir::FnDecl,
-                   blk: &hir::Block) {
-    debug!("regionck_fn(id={})", fn_id);
-    let mut rcx = RegionCtxt::new(self, RepeatingScope(blk.id), blk.id, Subject(fn_id));
-
-    if self.err_count_since_creation() == 0 {
-        // regionck assumes typeck succeeded
-        rcx.visit_fn_body(fn_id, decl, blk, fn_span);
+    pub fn regionck_expr(&self, e: &hir::Expr) {
+        let mut rcx = RegionCtxt::new(self, RepeatingScope(e.id), e.id, Subject(e.id));
+        if self.err_count_since_creation() == 0 {
+            // regionck assumes typeck succeeded
+            rcx.visit_expr(e);
+            rcx.visit_region_obligations(e.id);
+        }
+        rcx.resolve_regions_and_report_errors();
     }
 
-    rcx.free_region_map.relate_free_regions_from_predicates(
-        &self.parameter_environment.caller_bounds);
+    /// Region checking during the WF phase for items. `wf_tys` are the
+    /// types from which we should derive implied bounds, if any.
+    pub fn regionck_item(&self,
+                         item_id: ast::NodeId,
+                         span: Span,
+                         wf_tys: &[Ty<'tcx>]) {
+        debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys);
+        let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(item_id));
+        rcx.free_region_map.relate_free_regions_from_predicates(
+            &self.parameter_environment.caller_bounds);
+        rcx.relate_free_regions(wf_tys, item_id, span);
+        rcx.visit_region_obligations(item_id);
+        rcx.resolve_regions_and_report_errors();
+    }
 
-    rcx.resolve_regions_and_report_errors();
+    pub fn regionck_fn(&self,
+                       fn_id: ast::NodeId,
+                       fn_span: Span,
+                       decl: &hir::FnDecl,
+                       blk: &hir::Block) {
+        debug!("regionck_fn(id={})", fn_id);
+        let mut rcx = RegionCtxt::new(self, RepeatingScope(blk.id), blk.id, Subject(fn_id));
 
-    // For the top-level fn, store the free-region-map. We don't store
-    // any map for closures; they just share the same map as the
-    // function that created them.
-    self.tcx.store_free_region_map(fn_id, rcx.free_region_map);
-}
+        if self.err_count_since_creation() == 0 {
+            // regionck assumes typeck succeeded
+            rcx.visit_fn_body(fn_id, decl, blk, fn_span);
+        }
+
+        rcx.free_region_map.relate_free_regions_from_predicates(
+            &self.parameter_environment.caller_bounds);
+
+        rcx.resolve_regions_and_report_errors();
+
+        // For the top-level fn, store the free-region-map. We don't store
+        // any map for closures; they just share the same map as the
+        // function that created them.
+        self.tcx.store_free_region_map(fn_id, rcx.free_region_map);
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -449,42 +449,42 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                                                    subject_node_id);
     }
 
-fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
-    let tcx = self.tcx;
-    debug!("regionck::visit_pat(pat={:?})", pat);
-    pat_util::pat_bindings(&tcx.def_map, pat, |_, id, span, _| {
-        // If we have a variable that contains region'd data, that
-        // data will be accessible from anywhere that the variable is
-        // accessed. We must be wary of loops like this:
-        //
-        //     // from src/test/compile-fail/borrowck-lend-flow.rs
-        //     let mut v = box 3, w = box 4;
-        //     let mut x = &mut w;
-        //     loop {
-        //         **x += 1;   // (2)
-        //         borrow(v);  //~ ERROR cannot borrow
-        //         x = &mut v; // (1)
-        //     }
-        //
-        // Typically, we try to determine the region of a borrow from
-        // those points where it is dereferenced. In this case, one
-        // might imagine that the lifetime of `x` need only be the
-        // body of the loop. But of course this is incorrect because
-        // the pointer that is created at point (1) is consumed at
-        // point (2), meaning that it must be live across the loop
-        // iteration. The easiest way to guarantee this is to require
-        // that the lifetime of any regions that appear in a
-        // variable's type enclose at least the variable's scope.
+    fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
+        let tcx = self.tcx;
+        debug!("regionck::visit_pat(pat={:?})", pat);
+        pat_util::pat_bindings(&tcx.def_map, pat, |_, id, span, _| {
+            // If we have a variable that contains region'd data, that
+            // data will be accessible from anywhere that the variable is
+            // accessed. We must be wary of loops like this:
+            //
+            //     // from src/test/compile-fail/borrowck-lend-flow.rs
+            //     let mut v = box 3, w = box 4;
+            //     let mut x = &mut w;
+            //     loop {
+            //         **x += 1;   // (2)
+            //         borrow(v);  //~ ERROR cannot borrow
+            //         x = &mut v; // (1)
+            //     }
+            //
+            // Typically, we try to determine the region of a borrow from
+            // those points where it is dereferenced. In this case, one
+            // might imagine that the lifetime of `x` need only be the
+            // body of the loop. But of course this is incorrect because
+            // the pointer that is created at point (1) is consumed at
+            // point (2), meaning that it must be live across the loop
+            // iteration. The easiest way to guarantee this is to require
+            // that the lifetime of any regions that appear in a
+            // variable's type enclose at least the variable's scope.
 
-        let var_scope = tcx.region_maps.var_scope(id);
+            let var_scope = tcx.region_maps.var_scope(id);
 
-        let origin = infer::BindingTypeIsNotValidAtDecl(span);
-        self.type_of_node_must_outlive(origin, id, ty::ReScope(var_scope));
+            let origin = infer::BindingTypeIsNotValidAtDecl(span);
+            self.type_of_node_must_outlive(origin, id, ty::ReScope(var_scope));
 
-        let typ = self.resolve_node_type(id);
-        dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope);
-    })
-}
+            let typ = self.resolve_node_type(id);
+            dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope);
+        })
+    }
 }
 
 impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
@@ -518,296 +518,296 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
         intravisit::walk_local(self, l);
     }
 
-fn visit_expr(&mut self, expr: &hir::Expr) {
-    debug!("regionck::visit_expr(e={:?}, repeating_scope={})",
-           expr, self.repeating_scope);
+    fn visit_expr(&mut self, expr: &hir::Expr) {
+        debug!("regionck::visit_expr(e={:?}, repeating_scope={})",
+               expr, self.repeating_scope);
 
-    // No matter what, the type of each expression must outlive the
-    // scope of that expression. This also guarantees basic WF.
-    let expr_ty = self.resolve_node_type(expr.id);
-    // the region corresponding to this expression
-    let expr_region = ty::ReScope(self.tcx.region_maps.node_extent(expr.id));
-    self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span),
-                           expr_ty, expr_region);
+        // No matter what, the type of each expression must outlive the
+        // scope of that expression. This also guarantees basic WF.
+        let expr_ty = self.resolve_node_type(expr.id);
+        // the region corresponding to this expression
+        let expr_region = ty::ReScope(self.tcx.region_maps.node_extent(expr.id));
+        self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span),
+                               expr_ty, expr_region);
 
-    let method_call = MethodCall::expr(expr.id);
-    let opt_method_callee = self.tables.borrow().method_map.get(&method_call).cloned();
-    let has_method_map = opt_method_callee.is_some();
+        let method_call = MethodCall::expr(expr.id);
+        let opt_method_callee = self.tables.borrow().method_map.get(&method_call).cloned();
+        let has_method_map = opt_method_callee.is_some();
 
-    // If we are calling a method (either explicitly or via an
-    // overloaded operator), check that all of the types provided as
-    // arguments for its type parameters are well-formed, and all the regions
-    // provided as arguments outlive the call.
-    if let Some(callee) = opt_method_callee {
-        let origin = match expr.node {
-            hir::ExprMethodCall(..) =>
-                infer::ParameterOrigin::MethodCall,
-            hir::ExprUnary(op, _) if op == hir::UnDeref =>
-                infer::ParameterOrigin::OverloadedDeref,
-            _ =>
-                infer::ParameterOrigin::OverloadedOperator
-        };
+        // If we are calling a method (either explicitly or via an
+        // overloaded operator), check that all of the types provided as
+        // arguments for its type parameters are well-formed, and all the regions
+        // provided as arguments outlive the call.
+        if let Some(callee) = opt_method_callee {
+            let origin = match expr.node {
+                hir::ExprMethodCall(..) =>
+                    infer::ParameterOrigin::MethodCall,
+                hir::ExprUnary(op, _) if op == hir::UnDeref =>
+                    infer::ParameterOrigin::OverloadedDeref,
+                _ =>
+                    infer::ParameterOrigin::OverloadedOperator
+            };
 
-        self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region);
-        self.type_must_outlive(infer::ExprTypeIsNotInScope(callee.ty, expr.span),
-                               callee.ty, expr_region);
-    }
-
-    // Check any autoderefs or autorefs that appear.
-    let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
-    if let Some(adjustment) = adjustment {
-        debug!("adjustment={:?}", adjustment);
-        match adjustment {
-            adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
-                autoderefs, ref autoref, ..
-            }) => {
-                let expr_ty = self.resolve_node_type(expr.id);
-                self.constrain_autoderefs(expr, autoderefs, expr_ty);
-                if let Some(ref autoref) = *autoref {
-                    self.link_autoref(expr, autoderefs, autoref);
-
-                    // Require that the resulting region encompasses
-                    // the current node.
-                    //
-                    // FIXME(#6268) remove to support nested method calls
-                    self.type_of_node_must_outlive(infer::AutoBorrow(expr.span),
-                                                   expr.id, expr_region);
-                }
-            }
-            /*
-            adjustment::AutoObject(_, ref bounds, _, _) => {
-                // Determine if we are casting `expr` to a trait
-                // instance. If so, we have to be sure that the type
-                // of the source obeys the new region bound.
-                let source_ty = self.resolve_node_type(expr.id);
-                self.type_must_outlive(infer::RelateObjectBound(expr.span),
-                                       source_ty, bounds.region_bound);
-            }
-            */
-            _ => {}
+            self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region);
+            self.type_must_outlive(infer::ExprTypeIsNotInScope(callee.ty, expr.span),
+                                   callee.ty, expr_region);
         }
 
-        // If necessary, constrain destructors in the unadjusted form of this
-        // expression.
+        // Check any autoderefs or autorefs that appear.
+        let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
+        if let Some(adjustment) = adjustment {
+            debug!("adjustment={:?}", adjustment);
+            match adjustment {
+                adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
+                    autoderefs, ref autoref, ..
+                }) => {
+                    let expr_ty = self.resolve_node_type(expr.id);
+                    self.constrain_autoderefs(expr, autoderefs, expr_ty);
+                    if let Some(ref autoref) = *autoref {
+                        self.link_autoref(expr, autoderefs, autoref);
+
+                        // Require that the resulting region encompasses
+                        // the current node.
+                        //
+                        // FIXME(#6268) remove to support nested method calls
+                        self.type_of_node_must_outlive(infer::AutoBorrow(expr.span),
+                                                       expr.id, expr_region);
+                    }
+                }
+                /*
+                adjustment::AutoObject(_, ref bounds, _, _) => {
+                    // Determine if we are casting `expr` to a trait
+                    // instance. If so, we have to be sure that the type
+                    // of the source obeys the new region bound.
+                    let source_ty = self.resolve_node_type(expr.id);
+                    self.type_must_outlive(infer::RelateObjectBound(expr.span),
+                                           source_ty, bounds.region_bound);
+                }
+                */
+                _ => {}
+            }
+
+            // If necessary, constrain destructors in the unadjusted form of this
+            // expression.
+            let cmt_result = {
+                let mc = mc::MemCategorizationContext::new(self);
+                mc.cat_expr_unadjusted(expr)
+            };
+            match cmt_result {
+                Ok(head_cmt) => {
+                    self.check_safety_of_rvalue_destructor_if_necessary(head_cmt,
+                                                                        expr.span);
+                }
+                Err(..) => {
+                    self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd");
+                }
+            }
+        }
+
+        // If necessary, constrain destructors in this expression. This will be
+        // the adjusted form if there is an adjustment.
         let cmt_result = {
             let mc = mc::MemCategorizationContext::new(self);
-            mc.cat_expr_unadjusted(expr)
+            mc.cat_expr(expr)
         };
         match cmt_result {
             Ok(head_cmt) => {
-                self.check_safety_of_rvalue_destructor_if_necessary(head_cmt,
-                                                                    expr.span);
+                self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span);
             }
             Err(..) => {
-                self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd");
+                self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd");
             }
         }
-    }
 
-    // If necessary, constrain destructors in this expression. This will be
-    // the adjusted form if there is an adjustment.
-    let cmt_result = {
-        let mc = mc::MemCategorizationContext::new(self);
-        mc.cat_expr(expr)
-    };
-    match cmt_result {
-        Ok(head_cmt) => {
-            self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span);
-        }
-        Err(..) => {
-            self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd");
-        }
-    }
-
-    debug!("regionck::visit_expr(e={:?}, repeating_scope={}) - visiting subexprs",
-           expr, self.repeating_scope);
-    match expr.node {
-        hir::ExprPath(..) => {
-            self.fcx.opt_node_ty_substs(expr.id, |item_substs| {
-                let origin = infer::ParameterOrigin::Path;
-                self.substs_wf_in_scope(origin, &item_substs.substs, expr.span, expr_region);
-            });
-        }
-
-        hir::ExprCall(ref callee, ref args) => {
-            if has_method_map {
-                self.constrain_call(expr, Some(&callee),
-                                    args.iter().map(|e| &**e), false);
-            } else {
-                self.constrain_callee(callee.id, expr, &callee);
-                self.constrain_call(expr, None,
-                                    args.iter().map(|e| &**e), false);
+        debug!("regionck::visit_expr(e={:?}, repeating_scope={}) - visiting subexprs",
+               expr, self.repeating_scope);
+        match expr.node {
+            hir::ExprPath(..) => {
+                self.fcx.opt_node_ty_substs(expr.id, |item_substs| {
+                    let origin = infer::ParameterOrigin::Path;
+                    self.substs_wf_in_scope(origin, &item_substs.substs, expr.span, expr_region);
+                });
             }
 
-            intravisit::walk_expr(self, expr);
-        }
-
-        hir::ExprMethodCall(_, _, ref args) => {
-            self.constrain_call(expr, Some(&args[0]),
-                                args[1..].iter().map(|e| &**e), false);
-
-            intravisit::walk_expr(self, expr);
-        }
-
-        hir::ExprAssignOp(_, ref lhs, ref rhs) => {
-            if has_method_map {
-                self.constrain_call(expr, Some(&lhs),
-                                    Some(&**rhs).into_iter(), false);
-            }
-
-            intravisit::walk_expr(self, expr);
-        }
-
-        hir::ExprIndex(ref lhs, ref rhs) if has_method_map => {
-            self.constrain_call(expr, Some(&lhs),
-                                Some(&**rhs).into_iter(), true);
-
-            intravisit::walk_expr(self, expr);
-        },
-
-        hir::ExprBinary(op, ref lhs, ref rhs) if has_method_map => {
-            let implicitly_ref_args = !op.node.is_by_value();
-
-            // As `expr_method_call`, but the call is via an
-            // overloaded op.  Note that we (sadly) currently use an
-            // implicit "by ref" sort of passing style here.  This
-            // should be converted to an adjustment!
-            self.constrain_call(expr, Some(&lhs),
-                                Some(&**rhs).into_iter(), implicitly_ref_args);
-
-            intravisit::walk_expr(self, expr);
-        }
-
-        hir::ExprBinary(_, ref lhs, ref rhs) => {
-            // If you do `x OP y`, then the types of `x` and `y` must
-            // outlive the operation you are performing.
-            let lhs_ty = self.resolve_expr_type_adjusted(&lhs);
-            let rhs_ty = self.resolve_expr_type_adjusted(&rhs);
-            for &ty in &[lhs_ty, rhs_ty] {
-                self.type_must_outlive(infer::Operand(expr.span),
-                                       ty, expr_region);
-            }
-            intravisit::walk_expr(self, expr);
-        }
-
-        hir::ExprUnary(op, ref lhs) if has_method_map => {
-            let implicitly_ref_args = !op.is_by_value();
-
-            // As above.
-            self.constrain_call(expr, Some(&lhs),
-                                None::<hir::Expr>.iter(), implicitly_ref_args);
-
-            intravisit::walk_expr(self, expr);
-        }
-
-        hir::ExprUnary(hir::UnDeref, ref base) => {
-            // For *a, the lifetime of a must enclose the deref
-            let method_call = MethodCall::expr(expr.id);
-            let base_ty = match self.tables.borrow().method_map.get(&method_call) {
-                Some(method) => {
-                    self.constrain_call(expr, Some(&base),
-                                        None::<hir::Expr>.iter(), true);
-                    let fn_ret = // late-bound regions in overloaded method calls are instantiated
-                        self.tcx.no_late_bound_regions(&method.ty.fn_ret()).unwrap();
-                    fn_ret.unwrap()
+            hir::ExprCall(ref callee, ref args) => {
+                if has_method_map {
+                    self.constrain_call(expr, Some(&callee),
+                                        args.iter().map(|e| &**e), false);
+                } else {
+                    self.constrain_callee(callee.id, expr, &callee);
+                    self.constrain_call(expr, None,
+                                        args.iter().map(|e| &**e), false);
                 }
-                None => self.resolve_node_type(base.id)
-            };
-            if let ty::TyRef(r_ptr, _) = base_ty.sty {
-                self.mk_subregion_due_to_dereference(expr.span, expr_region, *r_ptr);
+
+                intravisit::walk_expr(self, expr);
             }
 
-            intravisit::walk_expr(self, expr);
-        }
+            hir::ExprMethodCall(_, _, ref args) => {
+                self.constrain_call(expr, Some(&args[0]),
+                                    args[1..].iter().map(|e| &**e), false);
 
-        hir::ExprIndex(ref vec_expr, _) => {
-            // For a[b], the lifetime of a must enclose the deref
-            let vec_type = self.resolve_expr_type_adjusted(&vec_expr);
-            self.constrain_index(expr, vec_type);
+                intravisit::walk_expr(self, expr);
+            }
 
-            intravisit::walk_expr(self, expr);
-        }
+            hir::ExprAssignOp(_, ref lhs, ref rhs) => {
+                if has_method_map {
+                    self.constrain_call(expr, Some(&lhs),
+                                        Some(&**rhs).into_iter(), false);
+                }
 
-        hir::ExprCast(ref source, _) => {
-            // Determine if we are casting `source` to a trait
-            // instance.  If so, we have to be sure that the type of
-            // the source obeys the trait's region bound.
-            self.constrain_cast(expr, &source);
-            intravisit::walk_expr(self, expr);
-        }
+                intravisit::walk_expr(self, expr);
+            }
 
-        hir::ExprAddrOf(m, ref base) => {
-            self.link_addr_of(expr, m, &base);
+            hir::ExprIndex(ref lhs, ref rhs) if has_method_map => {
+                self.constrain_call(expr, Some(&lhs),
+                                    Some(&**rhs).into_iter(), true);
 
-            // Require that when you write a `&expr` expression, the
-            // resulting pointer has a lifetime that encompasses the
-            // `&expr` expression itself. Note that we constraining
-            // the type of the node expr.id here *before applying
-            // adjustments*.
-            //
-            // FIXME(#6268) nested method calls requires that this rule change
-            let ty0 = self.resolve_node_type(expr.id);
-            self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region);
-            intravisit::walk_expr(self, expr);
-        }
+                intravisit::walk_expr(self, expr);
+            },
 
-        hir::ExprMatch(ref discr, ref arms, _) => {
-            self.link_match(&discr, &arms[..]);
+            hir::ExprBinary(op, ref lhs, ref rhs) if has_method_map => {
+                let implicitly_ref_args = !op.node.is_by_value();
 
-            intravisit::walk_expr(self, expr);
-        }
+                // As `expr_method_call`, but the call is via an
+                // overloaded op.  Note that we (sadly) currently use an
+                // implicit "by ref" sort of passing style here.  This
+                // should be converted to an adjustment!
+                self.constrain_call(expr, Some(&lhs),
+                                    Some(&**rhs).into_iter(), implicitly_ref_args);
 
-        hir::ExprClosure(_, _, ref body, _) => {
-            self.check_expr_fn_block(expr, &body);
-        }
+                intravisit::walk_expr(self, expr);
+            }
 
-        hir::ExprLoop(ref body, _) => {
-            let repeating_scope = self.set_repeating_scope(body.id);
-            intravisit::walk_expr(self, expr);
-            self.set_repeating_scope(repeating_scope);
-        }
+            hir::ExprBinary(_, ref lhs, ref rhs) => {
+                // If you do `x OP y`, then the types of `x` and `y` must
+                // outlive the operation you are performing.
+                let lhs_ty = self.resolve_expr_type_adjusted(&lhs);
+                let rhs_ty = self.resolve_expr_type_adjusted(&rhs);
+                for &ty in &[lhs_ty, rhs_ty] {
+                    self.type_must_outlive(infer::Operand(expr.span),
+                                           ty, expr_region);
+                }
+                intravisit::walk_expr(self, expr);
+            }
 
-        hir::ExprWhile(ref cond, ref body, _) => {
-            let repeating_scope = self.set_repeating_scope(cond.id);
-            self.visit_expr(&cond);
+            hir::ExprUnary(op, ref lhs) if has_method_map => {
+                let implicitly_ref_args = !op.is_by_value();
 
-            self.set_repeating_scope(body.id);
-            self.visit_block(&body);
+                // As above.
+                self.constrain_call(expr, Some(&lhs),
+                                    None::<hir::Expr>.iter(), implicitly_ref_args);
 
-            self.set_repeating_scope(repeating_scope);
-        }
+                intravisit::walk_expr(self, expr);
+            }
 
-        hir::ExprRet(Some(ref ret_expr)) => {
-            let call_site_scope = self.call_site_scope;
-            debug!("visit_expr ExprRet ret_expr.id {} call_site_scope: {:?}",
-                   ret_expr.id, call_site_scope);
-            self.type_of_node_must_outlive(infer::CallReturn(ret_expr.span),
-                                           ret_expr.id,
-                                           ty::ReScope(call_site_scope.unwrap()));
-            intravisit::walk_expr(self, expr);
-        }
+            hir::ExprUnary(hir::UnDeref, ref base) => {
+                // For *a, the lifetime of a must enclose the deref
+                let method_call = MethodCall::expr(expr.id);
+                let base_ty = match self.tables.borrow().method_map.get(&method_call) {
+                    Some(method) => {
+                        self.constrain_call(expr, Some(&base),
+                                            None::<hir::Expr>.iter(), true);
+                        // late-bound regions in overloaded method calls are instantiated
+                        let fn_ret = self.tcx.no_late_bound_regions(&method.ty.fn_ret());
+                        fn_ret.unwrap().unwrap()
+                    }
+                    None => self.resolve_node_type(base.id)
+                };
+                if let ty::TyRef(r_ptr, _) = base_ty.sty {
+                    self.mk_subregion_due_to_dereference(expr.span, expr_region, *r_ptr);
+                }
 
-        _ => {
-            intravisit::walk_expr(self, expr);
+                intravisit::walk_expr(self, expr);
+            }
+
+            hir::ExprIndex(ref vec_expr, _) => {
+                // For a[b], the lifetime of a must enclose the deref
+                let vec_type = self.resolve_expr_type_adjusted(&vec_expr);
+                self.constrain_index(expr, vec_type);
+
+                intravisit::walk_expr(self, expr);
+            }
+
+            hir::ExprCast(ref source, _) => {
+                // Determine if we are casting `source` to a trait
+                // instance.  If so, we have to be sure that the type of
+                // the source obeys the trait's region bound.
+                self.constrain_cast(expr, &source);
+                intravisit::walk_expr(self, expr);
+            }
+
+            hir::ExprAddrOf(m, ref base) => {
+                self.link_addr_of(expr, m, &base);
+
+                // Require that when you write a `&expr` expression, the
+                // resulting pointer has a lifetime that encompasses the
+                // `&expr` expression itself. Note that we constraining
+                // the type of the node expr.id here *before applying
+                // adjustments*.
+                //
+                // FIXME(#6268) nested method calls requires that this rule change
+                let ty0 = self.resolve_node_type(expr.id);
+                self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region);
+                intravisit::walk_expr(self, expr);
+            }
+
+            hir::ExprMatch(ref discr, ref arms, _) => {
+                self.link_match(&discr, &arms[..]);
+
+                intravisit::walk_expr(self, expr);
+            }
+
+            hir::ExprClosure(_, _, ref body, _) => {
+                self.check_expr_fn_block(expr, &body);
+            }
+
+            hir::ExprLoop(ref body, _) => {
+                let repeating_scope = self.set_repeating_scope(body.id);
+                intravisit::walk_expr(self, expr);
+                self.set_repeating_scope(repeating_scope);
+            }
+
+            hir::ExprWhile(ref cond, ref body, _) => {
+                let repeating_scope = self.set_repeating_scope(cond.id);
+                self.visit_expr(&cond);
+
+                self.set_repeating_scope(body.id);
+                self.visit_block(&body);
+
+                self.set_repeating_scope(repeating_scope);
+            }
+
+            hir::ExprRet(Some(ref ret_expr)) => {
+                let call_site_scope = self.call_site_scope;
+                debug!("visit_expr ExprRet ret_expr.id {} call_site_scope: {:?}",
+                       ret_expr.id, call_site_scope);
+                self.type_of_node_must_outlive(infer::CallReturn(ret_expr.span),
+                                               ret_expr.id,
+                                               ty::ReScope(call_site_scope.unwrap()));
+                intravisit::walk_expr(self, expr);
+            }
+
+            _ => {
+                intravisit::walk_expr(self, expr);
+            }
         }
     }
 }
-}
 
 impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
-fn constrain_cast(&mut self,
-                  cast_expr: &hir::Expr,
-                  source_expr: &hir::Expr)
-{
-    debug!("constrain_cast(cast_expr={:?}, source_expr={:?})",
-           cast_expr,
-           source_expr);
+    fn constrain_cast(&mut self,
+                      cast_expr: &hir::Expr,
+                      source_expr: &hir::Expr)
+    {
+        debug!("constrain_cast(cast_expr={:?}, source_expr={:?})",
+               cast_expr,
+               source_expr);
 
-    let source_ty = self.resolve_node_type(source_expr.id);
-    let target_ty = self.resolve_node_type(cast_expr.id);
+        let source_ty = self.resolve_node_type(source_expr.id);
+        let target_ty = self.resolve_node_type(cast_expr.id);
 
-    self.walk_cast(cast_expr, source_ty, target_ty);
-}
+        self.walk_cast(cast_expr, source_ty, target_ty);
+    }
 
     fn walk_cast(&mut self,
                  cast_expr: &hir::Expr,
@@ -841,984 +841,986 @@ fn constrain_cast(&mut self,
         }
     }
 
-fn check_expr_fn_block(&mut self,
-                       expr: &hir::Expr,
-                       body: &hir::Block) {
-    let repeating_scope = self.set_repeating_scope(body.id);
-    intravisit::walk_expr(self, expr);
-    self.set_repeating_scope(repeating_scope);
-}
-
-fn constrain_callee(&mut self,
-                    callee_id: ast::NodeId,
-                    _call_expr: &hir::Expr,
-                    _callee_expr: &hir::Expr) {
-    let callee_ty = self.resolve_node_type(callee_id);
-    match callee_ty.sty {
-        ty::TyFnDef(..) | ty::TyFnPtr(_) => { }
-        _ => {
-            // this should not happen, but it does if the program is
-            // erroneous
-            //
-            // bug!(
-            //     callee_expr.span,
-            //     "Calling non-function: {}",
-            //     callee_ty);
-        }
-    }
-}
-
-fn constrain_call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
-                                                       call_expr: &hir::Expr,
-                                                       receiver: Option<&hir::Expr>,
-                                                       arg_exprs: I,
-                                                       implicitly_ref_args: bool) {
-    //! Invoked on every call site (i.e., normal calls, method calls,
-    //! and overloaded operators). Constrains the regions which appear
-    //! in the type of the function. Also constrains the regions that
-    //! appear in the arguments appropriately.
-
-    debug!("constrain_call(call_expr={:?}, \
-            receiver={:?}, \
-            implicitly_ref_args={})",
-            call_expr,
-            receiver,
-            implicitly_ref_args);
-
-    // `callee_region` is the scope representing the time in which the
-    // call occurs.
-    //
-    // FIXME(#6268) to support nested method calls, should be callee_id
-    let callee_scope = self.tcx.region_maps.node_extent(call_expr.id);
-    let callee_region = ty::ReScope(callee_scope);
-
-    debug!("callee_region={:?}", callee_region);
-
-    for arg_expr in arg_exprs {
-        debug!("Argument: {:?}", arg_expr);
-
-        // ensure that any regions appearing in the argument type are
-        // valid for at least the lifetime of the function:
-        self.type_of_node_must_outlive(infer::CallArg(arg_expr.span),
-                                       arg_expr.id, callee_region);
-
-        // unfortunately, there are two means of taking implicit
-        // references, and we need to propagate constraints as a
-        // result. modes are going away and the "DerefArgs" code
-        // should be ported to use adjustments
-        if implicitly_ref_args {
-            self.link_by_ref(arg_expr, callee_scope);
-        }
+    fn check_expr_fn_block(&mut self,
+                           expr: &hir::Expr,
+                           body: &hir::Block) {
+        let repeating_scope = self.set_repeating_scope(body.id);
+        intravisit::walk_expr(self, expr);
+        self.set_repeating_scope(repeating_scope);
     }
 
-    // as loop above, but for receiver
-    if let Some(r) = receiver {
-        debug!("receiver: {:?}", r);
-        self.type_of_node_must_outlive(infer::CallRcvr(r.span),
-                                       r.id, callee_region);
-        if implicitly_ref_args {
-            self.link_by_ref(&r, callee_scope);
-        }
-    }
-}
-
-/// Invoked on any auto-dereference that occurs. Checks that if this is a region pointer being
-/// dereferenced, the lifetime of the pointer includes the deref expr.
-fn constrain_autoderefs(&mut self,
-                        deref_expr: &hir::Expr,
-                        derefs: usize,
-                        mut derefd_ty: Ty<'tcx>)
-{
-    debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})",
-           deref_expr,
-           derefs,
-           derefd_ty);
-
-    let s_deref_expr = self.tcx.region_maps.node_extent(deref_expr.id);
-    let r_deref_expr = ty::ReScope(s_deref_expr);
-    for i in 0..derefs {
-        let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
-        debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
-
-        let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone());
-
-        derefd_ty = match method {
-            Some(method) => {
-                debug!("constrain_autoderefs: #{} is overloaded, method={:?}",
-                       i, method);
-
-                let origin = infer::ParameterOrigin::OverloadedDeref;
-                self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr);
-
-                // Treat overloaded autoderefs as if an AutoRef adjustment
-                // was applied on the base type, as that is always the case.
-                let fn_sig = method.ty.fn_sig();
-                let fn_sig = // late-bound regions should have been instantiated
-                    self.tcx.no_late_bound_regions(fn_sig).unwrap();
-                let self_ty = fn_sig.inputs[0];
-                let (m, r) = match self_ty.sty {
-                    ty::TyRef(r, ref m) => (m.mutbl, r),
-                    _ => {
-                        span_bug!(
-                            deref_expr.span,
-                            "bad overloaded deref type {:?}",
-                            method.ty)
-                    }
-                };
-
-                debug!("constrain_autoderefs: receiver r={:?} m={:?}",
-                       r, m);
-
-                {
-                    let mc = mc::MemCategorizationContext::new(self);
-                    let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
-                    debug!("constrain_autoderefs: self_cmt={:?}",
-                           self_cmt);
-                    self.link_region(deref_expr.span, r,
-                                     ty::BorrowKind::from_mutbl(m), self_cmt);
-                }
-
-                // Specialized version of constrain_call.
-                self.type_must_outlive(infer::CallRcvr(deref_expr.span),
-                                       self_ty, r_deref_expr);
-                match fn_sig.output {
-                    ty::FnConverging(return_type) => {
-                        self.type_must_outlive(infer::CallReturn(deref_expr.span),
-                                               return_type, r_deref_expr);
-                        return_type
-                    }
-                    ty::FnDiverging => bug!()
-                }
-            }
-            None => derefd_ty
-        };
-
-        if let ty::TyRef(r_ptr, _) =  derefd_ty.sty {
-            self.mk_subregion_due_to_dereference(deref_expr.span,
-                                                 r_deref_expr, *r_ptr);
-        }
-
-        match derefd_ty.builtin_deref(true, ty::NoPreference) {
-            Some(mt) => derefd_ty = mt.ty,
-            /* if this type can't be dereferenced, then there's already an error
-               in the session saying so. Just bail out for now */
-            None => break
-        }
-    }
-}
-
-pub fn mk_subregion_due_to_dereference(&mut self,
-                                       deref_span: Span,
-                                       minimum_lifetime: ty::Region,
-                                       maximum_lifetime: ty::Region) {
-    self.sub_regions(infer::DerefPointer(deref_span),
-                     minimum_lifetime, maximum_lifetime)
-}
-
-fn check_safety_of_rvalue_destructor_if_necessary(&mut self,
-                                                 cmt: mc::cmt<'tcx>,
-                                                 span: Span) {
-    match cmt.cat {
-        Categorization::Rvalue(region) => {
-            match region {
-                ty::ReScope(rvalue_scope) => {
-                    let typ = self.resolve_type(cmt.ty);
-                    dropck::check_safety_of_destructor_if_necessary(self,
-                                                                    typ,
-                                                                    span,
-                                                                    rvalue_scope);
-                }
-                ty::ReStatic => {}
-                region => {
-                    span_bug!(span,
-                              "unexpected rvalue region in rvalue \
-                               destructor safety checking: `{:?}`",
-                              region);
-                }
+    fn constrain_callee(&mut self,
+                        callee_id: ast::NodeId,
+                        _call_expr: &hir::Expr,
+                        _callee_expr: &hir::Expr) {
+        let callee_ty = self.resolve_node_type(callee_id);
+        match callee_ty.sty {
+            ty::TyFnDef(..) | ty::TyFnPtr(_) => { }
+            _ => {
+                // this should not happen, but it does if the program is
+                // erroneous
+                //
+                // bug!(
+                //     callee_expr.span,
+                //     "Calling non-function: {}",
+                //     callee_ty);
             }
         }
-        _ => {}
     }
-}
 
-/// Invoked on any index expression that occurs. Checks that if this is a slice being indexed, the
-/// lifetime of the pointer includes the deref expr.
-fn constrain_index(&mut self,
-                   index_expr: &hir::Expr,
-                   indexed_ty: Ty<'tcx>)
-{
-    debug!("constrain_index(index_expr=?, indexed_ty={}",
-           self.ty_to_string(indexed_ty));
+    fn constrain_call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
+                                                           call_expr: &hir::Expr,
+                                                           receiver: Option<&hir::Expr>,
+                                                           arg_exprs: I,
+                                                           implicitly_ref_args: bool) {
+        //! Invoked on every call site (i.e., normal calls, method calls,
+        //! and overloaded operators). Constrains the regions which appear
+        //! in the type of the function. Also constrains the regions that
+        //! appear in the arguments appropriately.
 
-    let r_index_expr = ty::ReScope(self.tcx.region_maps.node_extent(index_expr.id));
-    if let ty::TyRef(r_ptr, mt) = indexed_ty.sty {
-        match mt.ty.sty {
-            ty::TySlice(_) | ty::TyStr => {
-                self.sub_regions(infer::IndexSlice(index_expr.span),
-                                 r_index_expr, *r_ptr);
+        debug!("constrain_call(call_expr={:?}, \
+                receiver={:?}, \
+                implicitly_ref_args={})",
+                call_expr,
+                receiver,
+                implicitly_ref_args);
+
+        // `callee_region` is the scope representing the time in which the
+        // call occurs.
+        //
+        // FIXME(#6268) to support nested method calls, should be callee_id
+        let callee_scope = self.tcx.region_maps.node_extent(call_expr.id);
+        let callee_region = ty::ReScope(callee_scope);
+
+        debug!("callee_region={:?}", callee_region);
+
+        for arg_expr in arg_exprs {
+            debug!("Argument: {:?}", arg_expr);
+
+            // ensure that any regions appearing in the argument type are
+            // valid for at least the lifetime of the function:
+            self.type_of_node_must_outlive(infer::CallArg(arg_expr.span),
+                                           arg_expr.id, callee_region);
+
+            // unfortunately, there are two means of taking implicit
+            // references, and we need to propagate constraints as a
+            // result. modes are going away and the "DerefArgs" code
+            // should be ported to use adjustments
+            if implicitly_ref_args {
+                self.link_by_ref(arg_expr, callee_scope);
+            }
+        }
+
+        // as loop above, but for receiver
+        if let Some(r) = receiver {
+            debug!("receiver: {:?}", r);
+            self.type_of_node_must_outlive(infer::CallRcvr(r.span),
+                                           r.id, callee_region);
+            if implicitly_ref_args {
+                self.link_by_ref(&r, callee_scope);
+            }
+        }
+    }
+
+    /// Invoked on any auto-dereference that occurs. Checks that if this is a region pointer being
+    /// dereferenced, the lifetime of the pointer includes the deref expr.
+    fn constrain_autoderefs(&mut self,
+                            deref_expr: &hir::Expr,
+                            derefs: usize,
+                            mut derefd_ty: Ty<'tcx>)
+    {
+        debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})",
+               deref_expr,
+               derefs,
+               derefd_ty);
+
+        let s_deref_expr = self.tcx.region_maps.node_extent(deref_expr.id);
+        let r_deref_expr = ty::ReScope(s_deref_expr);
+        for i in 0..derefs {
+            let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
+            debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
+
+            let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone());
+
+            derefd_ty = match method {
+                Some(method) => {
+                    debug!("constrain_autoderefs: #{} is overloaded, method={:?}",
+                           i, method);
+
+                    let origin = infer::ParameterOrigin::OverloadedDeref;
+                    self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr);
+
+                    // Treat overloaded autoderefs as if an AutoRef adjustment
+                    // was applied on the base type, as that is always the case.
+                    let fn_sig = method.ty.fn_sig();
+                    let fn_sig = // late-bound regions should have been instantiated
+                        self.tcx.no_late_bound_regions(fn_sig).unwrap();
+                    let self_ty = fn_sig.inputs[0];
+                    let (m, r) = match self_ty.sty {
+                        ty::TyRef(r, ref m) => (m.mutbl, r),
+                        _ => {
+                            span_bug!(
+                                deref_expr.span,
+                                "bad overloaded deref type {:?}",
+                                method.ty)
+                        }
+                    };
+
+                    debug!("constrain_autoderefs: receiver r={:?} m={:?}",
+                           r, m);
+
+                    {
+                        let mc = mc::MemCategorizationContext::new(self);
+                        let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
+                        debug!("constrain_autoderefs: self_cmt={:?}",
+                               self_cmt);
+                        self.link_region(deref_expr.span, r,
+                                         ty::BorrowKind::from_mutbl(m), self_cmt);
+                    }
+
+                    // Specialized version of constrain_call.
+                    self.type_must_outlive(infer::CallRcvr(deref_expr.span),
+                                           self_ty, r_deref_expr);
+                    match fn_sig.output {
+                        ty::FnConverging(return_type) => {
+                            self.type_must_outlive(infer::CallReturn(deref_expr.span),
+                                                   return_type, r_deref_expr);
+                            return_type
+                        }
+                        ty::FnDiverging => bug!()
+                    }
+                }
+                None => derefd_ty
+            };
+
+            if let ty::TyRef(r_ptr, _) =  derefd_ty.sty {
+                self.mk_subregion_due_to_dereference(deref_expr.span,
+                                                     r_deref_expr, *r_ptr);
+            }
+
+            match derefd_ty.builtin_deref(true, ty::NoPreference) {
+                Some(mt) => derefd_ty = mt.ty,
+                /* if this type can't be dereferenced, then there's already an error
+                   in the session saying so. Just bail out for now */
+                None => break
+            }
+        }
+    }
+
+    pub fn mk_subregion_due_to_dereference(&mut self,
+                                           deref_span: Span,
+                                           minimum_lifetime: ty::Region,
+                                           maximum_lifetime: ty::Region) {
+        self.sub_regions(infer::DerefPointer(deref_span),
+                         minimum_lifetime, maximum_lifetime)
+    }
+
+    fn check_safety_of_rvalue_destructor_if_necessary(&mut self,
+                                                     cmt: mc::cmt<'tcx>,
+                                                     span: Span) {
+        match cmt.cat {
+            Categorization::Rvalue(region) => {
+                match region {
+                    ty::ReScope(rvalue_scope) => {
+                        let typ = self.resolve_type(cmt.ty);
+                        dropck::check_safety_of_destructor_if_necessary(self,
+                                                                        typ,
+                                                                        span,
+                                                                        rvalue_scope);
+                    }
+                    ty::ReStatic => {}
+                    region => {
+                        span_bug!(span,
+                                  "unexpected rvalue region in rvalue \
+                                   destructor safety checking: `{:?}`",
+                                  region);
+                    }
+                }
             }
             _ => {}
         }
     }
-}
 
-/// Guarantees that any lifetimes which appear in the type of the node `id` (after applying
-/// adjustments) are valid for at least `minimum_lifetime`
-fn type_of_node_must_outlive(&mut self,
-    origin: infer::SubregionOrigin<'tcx>,
-    id: ast::NodeId,
-    minimum_lifetime: ty::Region)
-{
-    let tcx = self.tcx;
+    /// Invoked on any index expression that occurs. Checks that if this is a slice
+    /// being indexed, the lifetime of the pointer includes the deref expr.
+    fn constrain_index(&mut self,
+                       index_expr: &hir::Expr,
+                       indexed_ty: Ty<'tcx>)
+    {
+        debug!("constrain_index(index_expr=?, indexed_ty={}",
+               self.ty_to_string(indexed_ty));
 
-    // Try to resolve the type.  If we encounter an error, then typeck
-    // is going to fail anyway, so just stop here and let typeck
-    // report errors later on in the writeback phase.
-    let ty0 = self.resolve_node_type(id);
-    let ty = ty0.adjust(tcx, origin.span(), id,
-                        self.tables.borrow().adjustments.get(&id),
-                        |method_call| self.resolve_method_type(method_call));
-    debug!("constrain_regions_in_type_of_node(\
-            ty={}, ty0={}, id={}, minimum_lifetime={:?})",
-            ty,  ty0,
-           id, minimum_lifetime);
-    self.type_must_outlive(origin, ty, minimum_lifetime);
-}
-
-/// Computes the guarantor for an expression `&base` and then ensures that the lifetime of the
-/// resulting pointer is linked to the lifetime of its guarantor (if any).
-fn link_addr_of(&mut self, expr: &hir::Expr,
-                mutability: hir::Mutability, base: &hir::Expr) {
-    debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
-
-    let cmt = {
-        let mc = mc::MemCategorizationContext::new(self);
-        ignore_err!(mc.cat_expr(base))
-    };
-
-    debug!("link_addr_of: cmt={:?}", cmt);
-
-    self.link_region_from_node_type(expr.span, expr.id, mutability, cmt);
-}
-
-/// Computes the guarantors for any ref bindings in a `let` and
-/// then ensures that the lifetime of the resulting pointer is
-/// linked to the lifetime of the initialization expression.
-fn link_local(&self, local: &hir::Local) {
-    debug!("regionck::for_local()");
-    let init_expr = match local.init {
-        None => { return; }
-        Some(ref expr) => &**expr,
-    };
-    let mc = mc::MemCategorizationContext::new(self);
-    let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
-    self.link_pattern(mc, discr_cmt, &local.pat);
-}
-
-/// Computes the guarantors for any ref bindings in a match and
-/// then ensures that the lifetime of the resulting pointer is
-/// linked to the lifetime of its guarantor (if any).
-fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) {
-    debug!("regionck::for_match()");
-    let mc = mc::MemCategorizationContext::new(self);
-    let discr_cmt = ignore_err!(mc.cat_expr(discr));
-    debug!("discr_cmt={:?}", discr_cmt);
-    for arm in arms {
-        for root_pat in &arm.pats {
-            self.link_pattern(mc, discr_cmt.clone(), &root_pat);
-        }
-    }
-}
-
-/// Computes the guarantors for any ref bindings in a match and
-/// then ensures that the lifetime of the resulting pointer is
-/// linked to the lifetime of its guarantor (if any).
-fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) {
-    debug!("regionck::link_fn_args(body_scope={:?})", body_scope);
-    let mc = mc::MemCategorizationContext::new(self);
-    for arg in args {
-        let arg_ty = self.node_ty(arg.id);
-        let re_scope = ty::ReScope(body_scope);
-        let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
-        debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
-               arg_ty,
-               arg_cmt,
-               arg);
-        self.link_pattern(mc, arg_cmt, &arg.pat);
-    }
-}
-
-/// Link lifetimes of any ref bindings in `root_pat` to the pointers found in the discriminant, if
-/// needed.
-fn link_pattern<'t>(&self,
-                    mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>,
-                    discr_cmt: mc::cmt<'tcx>,
-                    root_pat: &hir::Pat) {
-    debug!("link_pattern(discr_cmt={:?}, root_pat={:?})",
-           discr_cmt,
-           root_pat);
-    let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
-            match sub_pat.node {
-                // `ref x` pattern
-                PatKind::Ident(hir::BindByRef(mutbl), _, _) => {
-                    self.link_region_from_node_type(sub_pat.span, sub_pat.id,
-                                                    mutbl, sub_cmt);
-                }
-
-                // `[_, ..slice, _]` pattern
-                PatKind::Vec(_, Some(ref slice_pat), _) => {
-                    match mc.cat_slice_pattern(sub_cmt, &slice_pat) {
-                        Ok((slice_cmt, slice_mutbl, slice_r)) => {
-                            self.link_region(sub_pat.span, &slice_r,
-                                             ty::BorrowKind::from_mutbl(slice_mutbl),
-                                             slice_cmt);
-                        }
-                        Err(()) => {}
-                    }
+        let r_index_expr = ty::ReScope(self.tcx.region_maps.node_extent(index_expr.id));
+        if let ty::TyRef(r_ptr, mt) = indexed_ty.sty {
+            match mt.ty.sty {
+                ty::TySlice(_) | ty::TyStr => {
+                    self.sub_regions(infer::IndexSlice(index_expr.span),
+                                     r_index_expr, *r_ptr);
                 }
                 _ => {}
             }
-        });
-}
-
-/// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being
-/// autoref'd.
-fn link_autoref(&self,
-                expr: &hir::Expr,
-                autoderefs: usize,
-                autoref: &adjustment::AutoRef)
-{
-    debug!("link_autoref(autoref={:?})", autoref);
-    let mc = mc::MemCategorizationContext::new(self);
-    let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
-    debug!("expr_cmt={:?}", expr_cmt);
-
-    match *autoref {
-        adjustment::AutoPtr(r, m) => {
-            self.link_region(expr.span, r,
-                             ty::BorrowKind::from_mutbl(m), expr_cmt);
-        }
-
-        adjustment::AutoUnsafe(m) => {
-            let r = ty::ReScope(self.tcx.region_maps.node_extent(expr.id));
-            self.link_region(expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt);
         }
     }
-}
 
-/// Computes the guarantor for cases where the `expr` is being passed by implicit reference and
-/// must outlive `callee_scope`.
-fn link_by_ref(&self,
-               expr: &hir::Expr,
-               callee_scope: CodeExtent) {
-    debug!("link_by_ref(expr={:?}, callee_scope={:?})",
-           expr, callee_scope);
-    let mc = mc::MemCategorizationContext::new(self);
-    let expr_cmt = ignore_err!(mc.cat_expr(expr));
-    let borrow_region = ty::ReScope(callee_scope);
-    self.link_region(expr.span, &borrow_region, ty::ImmBorrow, expr_cmt);
-}
+    /// Guarantees that any lifetimes which appear in the type of the node `id` (after applying
+    /// adjustments) are valid for at least `minimum_lifetime`
+    fn type_of_node_must_outlive(&mut self,
+        origin: infer::SubregionOrigin<'tcx>,
+        id: ast::NodeId,
+        minimum_lifetime: ty::Region)
+    {
+        let tcx = self.tcx;
 
-/// Like `link_region()`, except that the region is extracted from the type of `id`, which must be
-/// some reference (`&T`, `&str`, etc).
-fn link_region_from_node_type(&self,
-                              span: Span,
-                              id: ast::NodeId,
-                              mutbl: hir::Mutability,
-                              cmt_borrowed: mc::cmt<'tcx>) {
-    debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})",
-           id, mutbl, cmt_borrowed);
-
-    let rptr_ty = self.resolve_node_type(id);
-    if let ty::TyRef(&r, _) = rptr_ty.sty {
-        debug!("rptr_ty={}",  rptr_ty);
-        self.link_region(span, &r, ty::BorrowKind::from_mutbl(mutbl),
-                         cmt_borrowed);
+        // Try to resolve the type.  If we encounter an error, then typeck
+        // is going to fail anyway, so just stop here and let typeck
+        // report errors later on in the writeback phase.
+        let ty0 = self.resolve_node_type(id);
+        let ty = ty0.adjust(tcx, origin.span(), id,
+                            self.tables.borrow().adjustments.get(&id),
+                            |method_call| self.resolve_method_type(method_call));
+        debug!("constrain_regions_in_type_of_node(\
+                ty={}, ty0={}, id={}, minimum_lifetime={:?})",
+                ty,  ty0,
+               id, minimum_lifetime);
+        self.type_must_outlive(origin, ty, minimum_lifetime);
     }
-}
 
-/// Informs the inference engine that `borrow_cmt` is being borrowed with kind `borrow_kind` and
-/// lifetime `borrow_region`. In order to ensure borrowck is satisfied, this may create constraints
-/// between regions, as explained in `link_reborrowed_region()`.
-fn link_region(&self,
-               span: Span,
-               borrow_region: &ty::Region,
-               borrow_kind: ty::BorrowKind,
-               borrow_cmt: mc::cmt<'tcx>) {
-    let mut borrow_cmt = borrow_cmt;
-    let mut borrow_kind = borrow_kind;
+    /// Computes the guarantor for an expression `&base` and then ensures that the lifetime of the
+    /// resulting pointer is linked to the lifetime of its guarantor (if any).
+    fn link_addr_of(&mut self, expr: &hir::Expr,
+                    mutability: hir::Mutability, base: &hir::Expr) {
+        debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
 
-    let origin = infer::DataBorrowed(borrow_cmt.ty, span);
-    self.type_must_outlive(origin, borrow_cmt.ty, *borrow_region);
+        let cmt = {
+            let mc = mc::MemCategorizationContext::new(self);
+            ignore_err!(mc.cat_expr(base))
+        };
 
-    loop {
-        debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})",
-               borrow_region,
-               borrow_kind,
-               borrow_cmt);
-        match borrow_cmt.cat.clone() {
-            Categorization::Deref(ref_cmt, _,
-                                  mc::Implicit(ref_kind, ref_region)) |
-            Categorization::Deref(ref_cmt, _,
-                                  mc::BorrowedPtr(ref_kind, ref_region)) => {
-                match self.link_reborrowed_region(span,
-                                                  borrow_region, borrow_kind,
-                                                  ref_cmt, ref_region, ref_kind,
-                                                  borrow_cmt.note) {
-                    Some((c, k)) => {
-                        borrow_cmt = c;
-                        borrow_kind = k;
+        debug!("link_addr_of: cmt={:?}", cmt);
+
+        self.link_region_from_node_type(expr.span, expr.id, mutability, cmt);
+    }
+
+    /// Computes the guarantors for any ref bindings in a `let` and
+    /// then ensures that the lifetime of the resulting pointer is
+    /// linked to the lifetime of the initialization expression.
+    fn link_local(&self, local: &hir::Local) {
+        debug!("regionck::for_local()");
+        let init_expr = match local.init {
+            None => { return; }
+            Some(ref expr) => &**expr,
+        };
+        let mc = mc::MemCategorizationContext::new(self);
+        let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
+        self.link_pattern(mc, discr_cmt, &local.pat);
+    }
+
+    /// Computes the guarantors for any ref bindings in a match and
+    /// then ensures that the lifetime of the resulting pointer is
+    /// linked to the lifetime of its guarantor (if any).
+    fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) {
+        debug!("regionck::for_match()");
+        let mc = mc::MemCategorizationContext::new(self);
+        let discr_cmt = ignore_err!(mc.cat_expr(discr));
+        debug!("discr_cmt={:?}", discr_cmt);
+        for arm in arms {
+            for root_pat in &arm.pats {
+                self.link_pattern(mc, discr_cmt.clone(), &root_pat);
+            }
+        }
+    }
+
+    /// Computes the guarantors for any ref bindings in a match and
+    /// then ensures that the lifetime of the resulting pointer is
+    /// linked to the lifetime of its guarantor (if any).
+    fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) {
+        debug!("regionck::link_fn_args(body_scope={:?})", body_scope);
+        let mc = mc::MemCategorizationContext::new(self);
+        for arg in args {
+            let arg_ty = self.node_ty(arg.id);
+            let re_scope = ty::ReScope(body_scope);
+            let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
+            debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
+                   arg_ty,
+                   arg_cmt,
+                   arg);
+            self.link_pattern(mc, arg_cmt, &arg.pat);
+        }
+    }
+
+    /// Link lifetimes of any ref bindings in `root_pat` to the pointers found
+    /// in the discriminant, if needed.
+    fn link_pattern<'t>(&self,
+                        mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>,
+                        discr_cmt: mc::cmt<'tcx>,
+                        root_pat: &hir::Pat) {
+        debug!("link_pattern(discr_cmt={:?}, root_pat={:?})",
+               discr_cmt,
+               root_pat);
+        let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
+                match sub_pat.node {
+                    // `ref x` pattern
+                    PatKind::Ident(hir::BindByRef(mutbl), _, _) => {
+                        self.link_region_from_node_type(sub_pat.span, sub_pat.id,
+                                                        mutbl, sub_cmt);
                     }
-                    None => {
-                        return;
+
+                    // `[_, ..slice, _]` pattern
+                    PatKind::Vec(_, Some(ref slice_pat), _) => {
+                        match mc.cat_slice_pattern(sub_cmt, &slice_pat) {
+                            Ok((slice_cmt, slice_mutbl, slice_r)) => {
+                                self.link_region(sub_pat.span, &slice_r,
+                                                 ty::BorrowKind::from_mutbl(slice_mutbl),
+                                                 slice_cmt);
+                            }
+                            Err(()) => {}
+                        }
+                    }
+                    _ => {}
+                }
+            });
+    }
+
+    /// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being
+    /// autoref'd.
+    fn link_autoref(&self,
+                    expr: &hir::Expr,
+                    autoderefs: usize,
+                    autoref: &adjustment::AutoRef)
+    {
+        debug!("link_autoref(autoref={:?})", autoref);
+        let mc = mc::MemCategorizationContext::new(self);
+        let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
+        debug!("expr_cmt={:?}", expr_cmt);
+
+        match *autoref {
+            adjustment::AutoPtr(r, m) => {
+                self.link_region(expr.span, r,
+                                 ty::BorrowKind::from_mutbl(m), expr_cmt);
+            }
+
+            adjustment::AutoUnsafe(m) => {
+                let r = ty::ReScope(self.tcx.region_maps.node_extent(expr.id));
+                self.link_region(expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt);
+            }
+        }
+    }
+
+    /// Computes the guarantor for cases where the `expr` is being passed by implicit reference and
+    /// must outlive `callee_scope`.
+    fn link_by_ref(&self,
+                   expr: &hir::Expr,
+                   callee_scope: CodeExtent) {
+        debug!("link_by_ref(expr={:?}, callee_scope={:?})",
+               expr, callee_scope);
+        let mc = mc::MemCategorizationContext::new(self);
+        let expr_cmt = ignore_err!(mc.cat_expr(expr));
+        let borrow_region = ty::ReScope(callee_scope);
+        self.link_region(expr.span, &borrow_region, ty::ImmBorrow, expr_cmt);
+    }
+
+    /// Like `link_region()`, except that the region is extracted from the type of `id`,
+    /// which must be some reference (`&T`, `&str`, etc).
+    fn link_region_from_node_type(&self,
+                                  span: Span,
+                                  id: ast::NodeId,
+                                  mutbl: hir::Mutability,
+                                  cmt_borrowed: mc::cmt<'tcx>) {
+        debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})",
+               id, mutbl, cmt_borrowed);
+
+        let rptr_ty = self.resolve_node_type(id);
+        if let ty::TyRef(&r, _) = rptr_ty.sty {
+            debug!("rptr_ty={}",  rptr_ty);
+            self.link_region(span, &r, ty::BorrowKind::from_mutbl(mutbl),
+                             cmt_borrowed);
+        }
+    }
+
+    /// Informs the inference engine that `borrow_cmt` is being borrowed with
+    /// kind `borrow_kind` and lifetime `borrow_region`.
+    /// In order to ensure borrowck is satisfied, this may create constraints
+    /// between regions, as explained in `link_reborrowed_region()`.
+    fn link_region(&self,
+                   span: Span,
+                   borrow_region: &ty::Region,
+                   borrow_kind: ty::BorrowKind,
+                   borrow_cmt: mc::cmt<'tcx>) {
+        let mut borrow_cmt = borrow_cmt;
+        let mut borrow_kind = borrow_kind;
+
+        let origin = infer::DataBorrowed(borrow_cmt.ty, span);
+        self.type_must_outlive(origin, borrow_cmt.ty, *borrow_region);
+
+        loop {
+            debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})",
+                   borrow_region,
+                   borrow_kind,
+                   borrow_cmt);
+            match borrow_cmt.cat.clone() {
+                Categorization::Deref(ref_cmt, _,
+                                      mc::Implicit(ref_kind, ref_region)) |
+                Categorization::Deref(ref_cmt, _,
+                                      mc::BorrowedPtr(ref_kind, ref_region)) => {
+                    match self.link_reborrowed_region(span,
+                                                      borrow_region, borrow_kind,
+                                                      ref_cmt, ref_region, ref_kind,
+                                                      borrow_cmt.note) {
+                        Some((c, k)) => {
+                            borrow_cmt = c;
+                            borrow_kind = k;
+                        }
+                        None => {
+                            return;
+                        }
+                    }
+                }
+
+                Categorization::Downcast(cmt_base, _) |
+                Categorization::Deref(cmt_base, _, mc::Unique) |
+                Categorization::Interior(cmt_base, _) => {
+                    // Borrowing interior or owned data requires the base
+                    // to be valid and borrowable in the same fashion.
+                    borrow_cmt = cmt_base;
+                    borrow_kind = borrow_kind;
+                }
+
+                Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+                Categorization::StaticItem |
+                Categorization::Upvar(..) |
+                Categorization::Local(..) |
+                Categorization::Rvalue(..) => {
+                    // These are all "base cases" with independent lifetimes
+                    // that are not subject to inference
+                    return;
+                }
+            }
+        }
+    }
+
+    /// This is the most complicated case: the path being borrowed is
+    /// itself the referent of a borrowed pointer. Let me give an
+    /// example fragment of code to make clear(er) the situation:
+    ///
+    ///    let r: &'a mut T = ...;  // the original reference "r" has lifetime 'a
+    ///    ...
+    ///    &'z *r                   // the reborrow has lifetime 'z
+    ///
+    /// Now, in this case, our primary job is to add the inference
+    /// constraint that `'z <= 'a`. Given this setup, let's clarify the
+    /// parameters in (roughly) terms of the example:
+    ///
+    ///     A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T`
+    ///     borrow_region   ^~                 ref_region    ^~
+    ///     borrow_kind        ^~               ref_kind        ^~
+    ///     ref_cmt                 ^
+    ///
+    /// Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc).
+    ///
+    /// Unfortunately, there are some complications beyond the simple
+    /// scenario I just painted:
+    ///
+    /// 1. The reference `r` might in fact be a "by-ref" upvar. In that
+    ///    case, we have two jobs. First, we are inferring whether this reference
+    ///    should be an `&T`, `&mut T`, or `&uniq T` reference, and we must
+    ///    adjust that based on this borrow (e.g., if this is an `&mut` borrow,
+    ///    then `r` must be an `&mut` reference). Second, whenever we link
+    ///    two regions (here, `'z <= 'a`), we supply a *cause*, and in this
+    ///    case we adjust the cause to indicate that the reference being
+    ///    "reborrowed" is itself an upvar. This provides a nicer error message
+    ///    should something go wrong.
+    ///
+    /// 2. There may in fact be more levels of reborrowing. In the
+    ///    example, I said the borrow was like `&'z *r`, but it might
+    ///    in fact be a borrow like `&'z **q` where `q` has type `&'a
+    ///    &'b mut T`. In that case, we want to ensure that `'z <= 'a`
+    ///    and `'z <= 'b`. This is explained more below.
+    ///
+    /// The return value of this function indicates whether we need to
+    /// recurse and process `ref_cmt` (see case 2 above).
+    fn link_reborrowed_region(&self,
+                              span: Span,
+                              borrow_region: &ty::Region,
+                              borrow_kind: ty::BorrowKind,
+                              ref_cmt: mc::cmt<'tcx>,
+                              ref_region: ty::Region,
+                              mut ref_kind: ty::BorrowKind,
+                              note: mc::Note)
+                              -> Option<(mc::cmt<'tcx>, ty::BorrowKind)>
+    {
+        // Possible upvar ID we may need later to create an entry in the
+        // maybe link map.
+
+        // Detect by-ref upvar `x`:
+        let cause = match note {
+            mc::NoteUpvarRef(ref upvar_id) => {
+                let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map;
+                match upvar_capture_map.get(upvar_id) {
+                    Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
+                        // The mutability of the upvar may have been modified
+                        // by the above adjustment, so update our local variable.
+                        ref_kind = upvar_borrow.kind;
+
+                        infer::ReborrowUpvar(span, *upvar_id)
+                    }
+                    _ => {
+                        span_bug!( span, "Illegal upvar id: {:?}", upvar_id);
                     }
                 }
             }
+            mc::NoteClosureEnv(ref upvar_id) => {
+                // We don't have any mutability changes to propagate, but
+                // we do want to note that an upvar reborrow caused this
+                // link
+                infer::ReborrowUpvar(span, *upvar_id)
+            }
+            _ => {
+                infer::Reborrow(span)
+            }
+        };
 
-            Categorization::Downcast(cmt_base, _) |
-            Categorization::Deref(cmt_base, _, mc::Unique) |
-            Categorization::Interior(cmt_base, _) => {
-                // Borrowing interior or owned data requires the base
-                // to be valid and borrowable in the same fashion.
-                borrow_cmt = cmt_base;
-                borrow_kind = borrow_kind;
+        debug!("link_reborrowed_region: {:?} <= {:?}",
+               borrow_region,
+               ref_region);
+        self.sub_regions(cause, *borrow_region, ref_region);
+
+        // If we end up needing to recurse and establish a region link
+        // with `ref_cmt`, calculate what borrow kind we will end up
+        // needing. This will be used below.
+        //
+        // One interesting twist is that we can weaken the borrow kind
+        // when we recurse: to reborrow an `&mut` referent as mutable,
+        // borrowck requires a unique path to the `&mut` reference but not
+        // necessarily a *mutable* path.
+        let new_borrow_kind = match borrow_kind {
+            ty::ImmBorrow =>
+                ty::ImmBorrow,
+            ty::MutBorrow | ty::UniqueImmBorrow =>
+                ty::UniqueImmBorrow
+        };
+
+        // Decide whether we need to recurse and link any regions within
+        // the `ref_cmt`. This is concerned for the case where the value
+        // being reborrowed is in fact a borrowed pointer found within
+        // another borrowed pointer. For example:
+        //
+        //    let p: &'b &'a mut T = ...;
+        //    ...
+        //    &'z **p
+        //
+        // What makes this case particularly tricky is that, if the data
+        // being borrowed is a `&mut` or `&uniq` borrow, borrowck requires
+        // not only that `'z <= 'a`, (as before) but also `'z <= 'b`
+        // (otherwise the user might mutate through the `&mut T` reference
+        // after `'b` expires and invalidate the borrow we are looking at
+        // now).
+        //
+        // So let's re-examine our parameters in light of this more
+        // complicated (possible) scenario:
+        //
+        //     A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T`
+        //     borrow_region   ^~                 ref_region             ^~
+        //     borrow_kind        ^~               ref_kind                 ^~
+        //     ref_cmt                 ^~~
+        //
+        // (Note that since we have not examined `ref_cmt.cat`, we don't
+        // know whether this scenario has occurred; but I wanted to show
+        // how all the types get adjusted.)
+        match ref_kind {
+            ty::ImmBorrow => {
+                // The reference being reborrowed is a sharable ref of
+                // type `&'a T`. In this case, it doesn't matter where we
+                // *found* the `&T` pointer, the memory it references will
+                // be valid and immutable for `'a`. So we can stop here.
+                //
+                // (Note that the `borrow_kind` must also be ImmBorrow or
+                // else the user is borrowed imm memory as mut memory,
+                // which means they'll get an error downstream in borrowck
+                // anyhow.)
+                return None;
             }
 
-            Categorization::Deref(_, _, mc::UnsafePtr(..)) |
-            Categorization::StaticItem |
-            Categorization::Upvar(..) |
-            Categorization::Local(..) |
-            Categorization::Rvalue(..) => {
-                // These are all "base cases" with independent lifetimes
-                // that are not subject to inference
+            ty::MutBorrow | ty::UniqueImmBorrow => {
+                // The reference being reborrowed is either an `&mut T` or
+                // `&uniq T`. This is the case where recursion is needed.
+                return Some((ref_cmt, new_borrow_kind));
+            }
+        }
+    }
+
+    /// Checks that the values provided for type/region arguments in a given
+    /// expression are well-formed and in-scope.
+    fn substs_wf_in_scope(&mut self,
+                          origin: infer::ParameterOrigin,
+                          substs: &Substs<'tcx>,
+                          expr_span: Span,
+                          expr_region: ty::Region) {
+        debug!("substs_wf_in_scope(substs={:?}, \
+                expr_region={:?}, \
+                origin={:?}, \
+                expr_span={:?})",
+               substs, expr_region, origin, expr_span);
+
+        let origin = infer::ParameterInScope(origin, expr_span);
+
+        for &region in &substs.regions {
+            self.sub_regions(origin.clone(), expr_region, region);
+        }
+
+        for &ty in &substs.types {
+            let ty = self.resolve_type(ty);
+            self.type_must_outlive(origin.clone(), ty, expr_region);
+        }
+    }
+
+    /// Ensures that type is well-formed in `region`, which implies (among
+    /// other things) that all borrowed data reachable via `ty` outlives
+    /// `region`.
+    pub fn type_must_outlive(&self,
+                             origin: infer::SubregionOrigin<'tcx>,
+                             ty: Ty<'tcx>,
+                             region: ty::Region)
+    {
+        let ty = self.resolve_type(ty);
+
+        debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})",
+               ty,
+               region,
+               origin);
+
+        assert!(!ty.has_escaping_regions());
+
+        let components = self.outlives_components(ty);
+        self.components_must_outlive(origin, components, region);
+    }
+
+    fn components_must_outlive(&self,
+                               origin: infer::SubregionOrigin<'tcx>,
+                               components: Vec<ty::outlives::Component<'tcx>>,
+                               region: ty::Region)
+    {
+        for component in components {
+            let origin = origin.clone();
+            match component {
+                ty::outlives::Component::Region(region1) => {
+                    self.sub_regions(origin, region, region1);
+                }
+                ty::outlives::Component::Param(param_ty) => {
+                    self.param_ty_must_outlive(origin, region, param_ty);
+                }
+                ty::outlives::Component::Projection(projection_ty) => {
+                    self.projection_must_outlive(origin, region, projection_ty);
+                }
+                ty::outlives::Component::EscapingProjection(subcomponents) => {
+                    self.components_must_outlive(origin, subcomponents, region);
+                }
+                ty::outlives::Component::UnresolvedInferenceVariable(v) => {
+                    // ignore this, we presume it will yield an error
+                    // later, since if a type variable is not resolved by
+                    // this point it never will be
+                    self.tcx.sess.delay_span_bug(
+                        origin.span(),
+                        &format!("unresolved inference variable in outlives: {:?}", v));
+                }
+            }
+        }
+    }
+
+    fn param_ty_must_outlive(&self,
+                             origin: infer::SubregionOrigin<'tcx>,
+                             region: ty::Region,
+                             param_ty: ty::ParamTy) {
+        debug!("param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})",
+               region, param_ty, origin);
+
+        let verify_bound = self.param_bound(param_ty);
+        let generic = GenericKind::Param(param_ty);
+        self.verify_generic_bound(origin, generic, region, verify_bound);
+    }
+
+    fn projection_must_outlive(&self,
+                               origin: infer::SubregionOrigin<'tcx>,
+                               region: ty::Region,
+                               projection_ty: ty::ProjectionTy<'tcx>)
+    {
+        debug!("projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})",
+               region, projection_ty, origin);
+
+        // This case is thorny for inference. The fundamental problem is
+        // that there are many cases where we have choice, and inference
+        // doesn't like choice (the current region inference in
+        // particular). :) First off, we have to choose between using the
+        // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and
+        // OutlivesProjectionComponent rules, any one of which is
+        // sufficient.  If there are no inference variables involved, it's
+        // not hard to pick the right rule, but if there are, we're in a
+        // bit of a catch 22: if we picked which rule we were going to
+        // use, we could add constraints to the region inference graph
+        // that make it apply, but if we don't add those constraints, the
+        // rule might not apply (but another rule might). For now, we err
+        // on the side of adding too few edges into the graph.
+
+        // Compute the bounds we can derive from the environment or trait
+        // definition.  We know that the projection outlives all the
+        // regions in this list.
+        let env_bounds = self.projection_declared_bounds(origin.span(), projection_ty);
+
+        debug!("projection_must_outlive: env_bounds={:?}",
+               env_bounds);
+
+        // If we know that the projection outlives 'static, then we're
+        // done here.
+        if env_bounds.contains(&ty::ReStatic) {
+            debug!("projection_must_outlive: 'static as declared bound");
+            return;
+        }
+
+        // If declared bounds list is empty, the only applicable rule is
+        // OutlivesProjectionComponent. If there are inference variables,
+        // then, we can break down the outlives into more primitive
+        // components without adding unnecessary edges.
+        //
+        // If there are *no* inference variables, however, we COULD do
+        // this, but we choose not to, because the error messages are less
+        // good. For example, a requirement like `T::Item: 'r` would be
+        // translated to a requirement that `T: 'r`; when this is reported
+        // to the user, it will thus say "T: 'r must hold so that T::Item:
+        // 'r holds". But that makes it sound like the only way to fix
+        // the problem is to add `T: 'r`, which isn't true. So, if there are no
+        // inference variables, we use a verify constraint instead of adding
+        // edges, which winds up enforcing the same condition.
+        let needs_infer = {
+            projection_ty.trait_ref.substs.types.iter().any(|t| t.needs_infer()) ||
+                projection_ty.trait_ref.substs.regions.iter().any(|r| r.needs_infer())
+        };
+        if env_bounds.is_empty() && needs_infer {
+            debug!("projection_must_outlive: no declared bounds");
+
+            for &component_ty in &projection_ty.trait_ref.substs.types {
+                self.type_must_outlive(origin.clone(), component_ty, region);
+            }
+
+            for &r in &projection_ty.trait_ref.substs.regions {
+                self.sub_regions(origin.clone(), region, r);
+            }
+
+            return;
+        }
+
+        // If we find that there is a unique declared bound `'b`, and this bound
+        // appears in the trait reference, then the best action is to require that `'b:'r`,
+        // so do that. This is best no matter what rule we use:
+        //
+        // - OutlivesProjectionEnv or OutlivesProjectionTraitDef: these would translate to
+        // the requirement that `'b:'r`
+        // - OutlivesProjectionComponent: this would require `'b:'r` in addition to
+        // other conditions
+        if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) {
+            let unique_bound = env_bounds[0];
+            debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound);
+            if projection_ty.trait_ref.substs.regions
+                                             .iter()
+                                             .any(|r| env_bounds.contains(r))
+            {
+                debug!("projection_must_outlive: unique declared bound appears in trait ref");
+                self.sub_regions(origin.clone(), region, unique_bound);
                 return;
             }
         }
-    }
-}
 
-/// This is the most complicated case: the path being borrowed is
-/// itself the referent of a borrowed pointer. Let me give an
-/// example fragment of code to make clear(er) the situation:
-///
-///    let r: &'a mut T = ...;  // the original reference "r" has lifetime 'a
-///    ...
-///    &'z *r                   // the reborrow has lifetime 'z
-///
-/// Now, in this case, our primary job is to add the inference
-/// constraint that `'z <= 'a`. Given this setup, let's clarify the
-/// parameters in (roughly) terms of the example:
-///
-///     A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T`
-///     borrow_region   ^~                 ref_region    ^~
-///     borrow_kind        ^~               ref_kind        ^~
-///     ref_cmt                 ^
-///
-/// Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc).
-///
-/// Unfortunately, there are some complications beyond the simple
-/// scenario I just painted:
-///
-/// 1. The reference `r` might in fact be a "by-ref" upvar. In that
-///    case, we have two jobs. First, we are inferring whether this reference
-///    should be an `&T`, `&mut T`, or `&uniq T` reference, and we must
-///    adjust that based on this borrow (e.g., if this is an `&mut` borrow,
-///    then `r` must be an `&mut` reference). Second, whenever we link
-///    two regions (here, `'z <= 'a`), we supply a *cause*, and in this
-///    case we adjust the cause to indicate that the reference being
-///    "reborrowed" is itself an upvar. This provides a nicer error message
-///    should something go wrong.
-///
-/// 2. There may in fact be more levels of reborrowing. In the
-///    example, I said the borrow was like `&'z *r`, but it might
-///    in fact be a borrow like `&'z **q` where `q` has type `&'a
-///    &'b mut T`. In that case, we want to ensure that `'z <= 'a`
-///    and `'z <= 'b`. This is explained more below.
-///
-/// The return value of this function indicates whether we need to
-/// recurse and process `ref_cmt` (see case 2 above).
-fn link_reborrowed_region(&self,
-                          span: Span,
-                          borrow_region: &ty::Region,
-                          borrow_kind: ty::BorrowKind,
-                          ref_cmt: mc::cmt<'tcx>,
-                          ref_region: ty::Region,
-                          mut ref_kind: ty::BorrowKind,
-                          note: mc::Note)
-                          -> Option<(mc::cmt<'tcx>, ty::BorrowKind)>
-{
-    // Possible upvar ID we may need later to create an entry in the
-    // maybe link map.
-
-    // Detect by-ref upvar `x`:
-    let cause = match note {
-        mc::NoteUpvarRef(ref upvar_id) => {
-            let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map;
-            match upvar_capture_map.get(upvar_id) {
-                Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
-                    // The mutability of the upvar may have been modified
-                    // by the above adjustment, so update our local variable.
-                    ref_kind = upvar_borrow.kind;
-
-                    infer::ReborrowUpvar(span, *upvar_id)
-                }
-                _ => {
-                    span_bug!( span, "Illegal upvar id: {:?}", upvar_id);
-                }
-            }
-        }
-        mc::NoteClosureEnv(ref upvar_id) => {
-            // We don't have any mutability changes to propagate, but
-            // we do want to note that an upvar reborrow caused this
-            // link
-            infer::ReborrowUpvar(span, *upvar_id)
-        }
-        _ => {
-            infer::Reborrow(span)
-        }
-    };
-
-    debug!("link_reborrowed_region: {:?} <= {:?}",
-           borrow_region,
-           ref_region);
-    self.sub_regions(cause, *borrow_region, ref_region);
-
-    // If we end up needing to recurse and establish a region link
-    // with `ref_cmt`, calculate what borrow kind we will end up
-    // needing. This will be used below.
-    //
-    // One interesting twist is that we can weaken the borrow kind
-    // when we recurse: to reborrow an `&mut` referent as mutable,
-    // borrowck requires a unique path to the `&mut` reference but not
-    // necessarily a *mutable* path.
-    let new_borrow_kind = match borrow_kind {
-        ty::ImmBorrow =>
-            ty::ImmBorrow,
-        ty::MutBorrow | ty::UniqueImmBorrow =>
-            ty::UniqueImmBorrow
-    };
-
-    // Decide whether we need to recurse and link any regions within
-    // the `ref_cmt`. This is concerned for the case where the value
-    // being reborrowed is in fact a borrowed pointer found within
-    // another borrowed pointer. For example:
-    //
-    //    let p: &'b &'a mut T = ...;
-    //    ...
-    //    &'z **p
-    //
-    // What makes this case particularly tricky is that, if the data
-    // being borrowed is a `&mut` or `&uniq` borrow, borrowck requires
-    // not only that `'z <= 'a`, (as before) but also `'z <= 'b`
-    // (otherwise the user might mutate through the `&mut T` reference
-    // after `'b` expires and invalidate the borrow we are looking at
-    // now).
-    //
-    // So let's re-examine our parameters in light of this more
-    // complicated (possible) scenario:
-    //
-    //     A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T`
-    //     borrow_region   ^~                 ref_region             ^~
-    //     borrow_kind        ^~               ref_kind                 ^~
-    //     ref_cmt                 ^~~
-    //
-    // (Note that since we have not examined `ref_cmt.cat`, we don't
-    // know whether this scenario has occurred; but I wanted to show
-    // how all the types get adjusted.)
-    match ref_kind {
-        ty::ImmBorrow => {
-            // The reference being reborrowed is a sharable ref of
-            // type `&'a T`. In this case, it doesn't matter where we
-            // *found* the `&T` pointer, the memory it references will
-            // be valid and immutable for `'a`. So we can stop here.
-            //
-            // (Note that the `borrow_kind` must also be ImmBorrow or
-            // else the user is borrowed imm memory as mut memory,
-            // which means they'll get an error downstream in borrowck
-            // anyhow.)
-            return None;
-        }
-
-        ty::MutBorrow | ty::UniqueImmBorrow => {
-            // The reference being reborrowed is either an `&mut T` or
-            // `&uniq T`. This is the case where recursion is needed.
-            return Some((ref_cmt, new_borrow_kind));
-        }
-    }
-}
-
-/// Checks that the values provided for type/region arguments in a given
-/// expression are well-formed and in-scope.
-fn substs_wf_in_scope(&mut self,
-                      origin: infer::ParameterOrigin,
-                      substs: &Substs<'tcx>,
-                      expr_span: Span,
-                      expr_region: ty::Region) {
-    debug!("substs_wf_in_scope(substs={:?}, \
-            expr_region={:?}, \
-            origin={:?}, \
-            expr_span={:?})",
-           substs, expr_region, origin, expr_span);
-
-    let origin = infer::ParameterInScope(origin, expr_span);
-
-    for &region in &substs.regions {
-        self.sub_regions(origin.clone(), expr_region, region);
+        // Fallback to verifying after the fact that there exists a
+        // declared bound, or that all the components appearing in the
+        // projection outlive; in some cases, this may add insufficient
+        // edges into the inference graph, leading to inference failures
+        // even though a satisfactory solution exists.
+        let verify_bound = self.projection_bound(origin.span(), env_bounds, projection_ty);
+        let generic = GenericKind::Projection(projection_ty);
+        self.verify_generic_bound(origin, generic.clone(), region, verify_bound);
     }
 
-    for &ty in &substs.types {
-        let ty = self.resolve_type(ty);
-        self.type_must_outlive(origin.clone(), ty, expr_region);
-    }
-}
-
-/// Ensures that type is well-formed in `region`, which implies (among
-/// other things) that all borrowed data reachable via `ty` outlives
-/// `region`.
-pub fn type_must_outlive(&self,
-                         origin: infer::SubregionOrigin<'tcx>,
-                         ty: Ty<'tcx>,
-                         region: ty::Region)
-{
-    let ty = self.resolve_type(ty);
-
-    debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})",
-           ty,
-           region,
-           origin);
-
-    assert!(!ty.has_escaping_regions());
-
-    let components = self.outlives_components(ty);
-    self.components_must_outlive(origin, components, region);
-}
-
-fn components_must_outlive(&self,
-                           origin: infer::SubregionOrigin<'tcx>,
-                           components: Vec<ty::outlives::Component<'tcx>>,
-                           region: ty::Region)
-{
-    for component in components {
-        let origin = origin.clone();
-        match component {
-            ty::outlives::Component::Region(region1) => {
-                self.sub_regions(origin, region, region1);
+    fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
+        match ty.sty {
+            ty::TyParam(p) => {
+                self.param_bound(p)
             }
-            ty::outlives::Component::Param(param_ty) => {
-                self.param_ty_must_outlive(origin, region, param_ty);
+            ty::TyProjection(data) => {
+                let declared_bounds = self.projection_declared_bounds(span, data);
+                self.projection_bound(span, declared_bounds, data)
             }
-            ty::outlives::Component::Projection(projection_ty) => {
-                self.projection_must_outlive(origin, region, projection_ty);
-            }
-            ty::outlives::Component::EscapingProjection(subcomponents) => {
-                self.components_must_outlive(origin, subcomponents, region);
-            }
-            ty::outlives::Component::UnresolvedInferenceVariable(v) => {
-                // ignore this, we presume it will yield an error
-                // later, since if a type variable is not resolved by
-                // this point it never will be
-                self.tcx.sess.delay_span_bug(
-                    origin.span(),
-                    &format!("unresolved inference variable in outlives: {:?}", v));
+            _ => {
+                self.recursive_type_bound(span, ty)
             }
         }
     }
-}
 
-fn param_ty_must_outlive(&self,
-                         origin: infer::SubregionOrigin<'tcx>,
-                         region: ty::Region,
-                         param_ty: ty::ParamTy) {
-    debug!("param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})",
-           region, param_ty, origin);
+    fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound {
+        let param_env = &self.parameter_environment;
 
-    let verify_bound = self.param_bound(param_ty);
-    let generic = GenericKind::Param(param_ty);
-    self.verify_generic_bound(origin, generic, region, verify_bound);
-}
+        debug!("param_bound(param_ty={:?})",
+               param_ty);
 
-fn projection_must_outlive(&self,
-                           origin: infer::SubregionOrigin<'tcx>,
-                           region: ty::Region,
-                           projection_ty: ty::ProjectionTy<'tcx>)
-{
-    debug!("projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})",
-           region, projection_ty, origin);
+        let mut param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty));
 
-    // This case is thorny for inference. The fundamental problem is
-    // that there are many cases where we have choice, and inference
-    // doesn't like choice (the current region inference in
-    // particular). :) First off, we have to choose between using the
-    // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and
-    // OutlivesProjectionComponent rules, any one of which is
-    // sufficient.  If there are no inference variables involved, it's
-    // not hard to pick the right rule, but if there are, we're in a
-    // bit of a catch 22: if we picked which rule we were going to
-    // use, we could add constraints to the region inference graph
-    // that make it apply, but if we don't add those constraints, the
-    // rule might not apply (but another rule might). For now, we err
-    // on the side of adding too few edges into the graph.
+        // Add in the default bound of fn body that applies to all in
+        // scope type parameters:
+        param_bounds.push(param_env.implicit_region_bound);
 
-    // Compute the bounds we can derive from the environment or trait
-    // definition.  We know that the projection outlives all the
-    // regions in this list.
-    let env_bounds = self.projection_declared_bounds(origin.span(), projection_ty);
-
-    debug!("projection_must_outlive: env_bounds={:?}",
-           env_bounds);
-
-    // If we know that the projection outlives 'static, then we're
-    // done here.
-    if env_bounds.contains(&ty::ReStatic) {
-        debug!("projection_must_outlive: 'static as declared bound");
-        return;
+        VerifyBound::AnyRegion(param_bounds)
     }
 
-    // If declared bounds list is empty, the only applicable rule is
-    // OutlivesProjectionComponent. If there are inference variables,
-    // then, we can break down the outlives into more primitive
-    // components without adding unnecessary edges.
-    //
-    // If there are *no* inference variables, however, we COULD do
-    // this, but we choose not to, because the error messages are less
-    // good. For example, a requirement like `T::Item: 'r` would be
-    // translated to a requirement that `T: 'r`; when this is reported
-    // to the user, it will thus say "T: 'r must hold so that T::Item:
-    // 'r holds". But that makes it sound like the only way to fix
-    // the problem is to add `T: 'r`, which isn't true. So, if there are no
-    // inference variables, we use a verify constraint instead of adding
-    // edges, which winds up enforcing the same condition.
-    let needs_infer = {
-        projection_ty.trait_ref.substs.types.iter().any(|t| t.needs_infer()) ||
-            projection_ty.trait_ref.substs.regions.iter().any(|r| r.needs_infer())
-    };
-    if env_bounds.is_empty() && needs_infer {
-        debug!("projection_must_outlive: no declared bounds");
+    fn projection_declared_bounds(&self,
+                                  span: Span,
+                                  projection_ty: ty::ProjectionTy<'tcx>)
+                                  -> Vec<ty::Region>
+    {
+        // First assemble bounds from where clauses and traits.
 
-        for &component_ty in &projection_ty.trait_ref.substs.types {
-            self.type_must_outlive(origin.clone(), component_ty, region);
-        }
+        let mut declared_bounds =
+            self.declared_generic_bounds_from_env(GenericKind::Projection(projection_ty));
 
-        for &r in &projection_ty.trait_ref.substs.regions {
-            self.sub_regions(origin.clone(), region, r);
-        }
+        declared_bounds.extend_from_slice(
+            &self.declared_projection_bounds_from_trait(span, projection_ty));
 
-        return;
+        declared_bounds
     }
 
-    // If we find that there is a unique declared bound `'b`, and this bound
-    // appears in the trait reference, then the best action is to require that `'b:'r`,
-    // so do that. This is best no matter what rule we use:
-    //
-    // - OutlivesProjectionEnv or OutlivesProjectionTraitDef: these would translate to
-    // the requirement that `'b:'r`
-    // - OutlivesProjectionComponent: this would require `'b:'r` in addition to other conditions
-    if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) {
-        let unique_bound = env_bounds[0];
-        debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound);
-        if projection_ty.trait_ref.substs.regions
-                                         .iter()
-                                         .any(|r| env_bounds.contains(r))
-        {
-            debug!("projection_must_outlive: unique declared bound appears in trait ref");
-            self.sub_regions(origin.clone(), region, unique_bound);
-            return;
+    fn projection_bound(&self,
+                        span: Span,
+                        declared_bounds: Vec<ty::Region>,
+                        projection_ty: ty::ProjectionTy<'tcx>)
+                        -> VerifyBound {
+        debug!("projection_bound(declared_bounds={:?}, projection_ty={:?})",
+               declared_bounds, projection_ty);
+
+        // see the extensive comment in projection_must_outlive
+
+        let ty = self.tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name);
+        let recursive_bound = self.recursive_type_bound(span, ty);
+
+        VerifyBound::AnyRegion(declared_bounds).or(recursive_bound)
+    }
+
+    fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
+        let mut bounds = vec![];
+
+        for subty in ty.walk_shallow() {
+            bounds.push(self.type_bound(span, subty));
+        }
+
+        let mut regions = ty.regions();
+        regions.retain(|r| !r.is_bound()); // ignore late-bound regions
+        bounds.push(VerifyBound::AllRegions(regions));
+
+        // remove bounds that must hold, since they are not interesting
+        bounds.retain(|b| !b.must_hold());
+
+        if bounds.len() == 1 {
+            bounds.pop().unwrap()
+        } else {
+            VerifyBound::AllBounds(bounds)
         }
     }
 
-    // Fallback to verifying after the fact that there exists a
-    // declared bound, or that all the components appearing in the
-    // projection outlive; in some cases, this may add insufficient
-    // edges into the inference graph, leading to inference failures
-    // even though a satisfactory solution exists.
-    let verify_bound = self.projection_bound(origin.span(), env_bounds, projection_ty);
-    let generic = GenericKind::Projection(projection_ty);
-    self.verify_generic_bound(origin, generic.clone(), region, verify_bound);
-}
+    fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>)
+                                        -> Vec<ty::Region>
+    {
+        let param_env = &self.parameter_environment;
 
-fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
-    match ty.sty {
-        ty::TyParam(p) => {
-            self.param_bound(p)
+        // To start, collect bounds from user:
+        let mut param_bounds = self.tcx.required_region_bounds(generic.to_ty(self.tcx),
+                                                               param_env.caller_bounds.clone());
+
+        // Next, collect regions we scraped from the well-formedness
+        // constraints in the fn signature. To do that, we walk the list
+        // of known relations from the fn ctxt.
+        //
+        // This is crucial because otherwise code like this fails:
+        //
+        //     fn foo<'a, A>(x: &'a A) { x.bar() }
+        //
+        // The problem is that the type of `x` is `&'a A`. To be
+        // well-formed, then, A must be lower-generic by `'a`, but we
+        // don't know that this holds from first principles.
+        for &(r, p) in &self.region_bound_pairs {
+            debug!("generic={:?} p={:?}",
+                   generic,
+                   p);
+            if generic == p {
+                param_bounds.push(r);
+            }
         }
-        ty::TyProjection(data) => {
-            let declared_bounds = self.projection_declared_bounds(span, data);
-            self.projection_bound(span, declared_bounds, data)
-        }
-        _ => {
-            self.recursive_type_bound(span, ty)
-        }
-    }
-}
 
-fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound {
-    let param_env = &self.parameter_environment;
-
-    debug!("param_bound(param_ty={:?})",
-           param_ty);
-
-    let mut param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty));
-
-    // Add in the default bound of fn body that applies to all in
-    // scope type parameters:
-    param_bounds.push(param_env.implicit_region_bound);
-
-    VerifyBound::AnyRegion(param_bounds)
-}
-
-fn projection_declared_bounds(&self,
-                              span: Span,
-                              projection_ty: ty::ProjectionTy<'tcx>)
-                              -> Vec<ty::Region>
-{
-    // First assemble bounds from where clauses and traits.
-
-    let mut declared_bounds =
-        self.declared_generic_bounds_from_env(GenericKind::Projection(projection_ty));
-
-    declared_bounds.extend_from_slice(
-        &self.declared_projection_bounds_from_trait(span, projection_ty));
-
-    declared_bounds
-}
-
-fn projection_bound(&self,
-                    span: Span,
-                    declared_bounds: Vec<ty::Region>,
-                    projection_ty: ty::ProjectionTy<'tcx>)
-                    -> VerifyBound {
-    debug!("projection_bound(declared_bounds={:?}, projection_ty={:?})",
-           declared_bounds, projection_ty);
-
-    // see the extensive comment in projection_must_outlive
-
-    let ty = self.tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name);
-    let recursive_bound = self.recursive_type_bound(span, ty);
-
-    VerifyBound::AnyRegion(declared_bounds).or(recursive_bound)
-}
-
-fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
-    let mut bounds = vec![];
-
-    for subty in ty.walk_shallow() {
-        bounds.push(self.type_bound(span, subty));
+        param_bounds
     }
 
-    let mut regions = ty.regions();
-    regions.retain(|r| !r.is_bound()); // ignore late-bound regions
-    bounds.push(VerifyBound::AllRegions(regions));
+    fn declared_projection_bounds_from_trait(&self,
+                                             span: Span,
+                                             projection_ty: ty::ProjectionTy<'tcx>)
+                                             -> Vec<ty::Region>
+    {
+        debug!("projection_bounds(projection_ty={:?})",
+               projection_ty);
 
-    // remove bounds that must hold, since they are not interesting
-    bounds.retain(|b| !b.must_hold());
+        let ty = self.tcx.mk_projection(projection_ty.trait_ref.clone(),
+                                        projection_ty.item_name);
 
-    if bounds.len() == 1 {
-        bounds.pop().unwrap()
-    } else {
-        VerifyBound::AllBounds(bounds)
-    }
-}
+        // Say we have a projection `<T as SomeTrait<'a>>::SomeType`. We are interested
+        // in looking for a trait definition like:
+        //
+        // ```
+        // trait SomeTrait<'a> {
+        //     type SomeType : 'a;
+        // }
+        // ```
+        //
+        // we can thus deduce that `<T as SomeTrait<'a>>::SomeType : 'a`.
+        let trait_predicates = self.tcx.lookup_predicates(projection_ty.trait_ref.def_id);
+        let predicates = trait_predicates.predicates.as_slice().to_vec();
+        traits::elaborate_predicates(self.tcx, predicates)
+            .filter_map(|predicate| {
+                // we're only interesting in `T : 'a` style predicates:
+                let outlives = match predicate {
+                    ty::Predicate::TypeOutlives(data) => data,
+                    _ => { return None; }
+                };
 
-fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>)
-                                    -> Vec<ty::Region>
-{
-    let param_env = &self.parameter_environment;
-
-    // To start, collect bounds from user:
-    let mut param_bounds = self.tcx.required_region_bounds(generic.to_ty(self.tcx),
-                                                           param_env.caller_bounds.clone());
-
-    // Next, collect regions we scraped from the well-formedness
-    // constraints in the fn signature. To do that, we walk the list
-    // of known relations from the fn ctxt.
-    //
-    // This is crucial because otherwise code like this fails:
-    //
-    //     fn foo<'a, A>(x: &'a A) { x.bar() }
-    //
-    // The problem is that the type of `x` is `&'a A`. To be
-    // well-formed, then, A must be lower-generic by `'a`, but we
-    // don't know that this holds from first principles.
-    for &(r, p) in &self.region_bound_pairs {
-        debug!("generic={:?} p={:?}",
-               generic,
-               p);
-        if generic == p {
-            param_bounds.push(r);
-        }
-    }
-
-    param_bounds
-}
-
-fn declared_projection_bounds_from_trait(&self,
-                                         span: Span,
-                                         projection_ty: ty::ProjectionTy<'tcx>)
-                                         -> Vec<ty::Region>
-{
-    debug!("projection_bounds(projection_ty={:?})",
-           projection_ty);
-
-    let ty = self.tcx.mk_projection(projection_ty.trait_ref.clone(),
-                                    projection_ty.item_name);
-
-    // Say we have a projection `<T as SomeTrait<'a>>::SomeType`. We are interested
-    // in looking for a trait definition like:
-    //
-    // ```
-    // trait SomeTrait<'a> {
-    //     type SomeType : 'a;
-    // }
-    // ```
-    //
-    // we can thus deduce that `<T as SomeTrait<'a>>::SomeType : 'a`.
-    let trait_predicates = self.tcx.lookup_predicates(projection_ty.trait_ref.def_id);
-    let predicates = trait_predicates.predicates.as_slice().to_vec();
-    traits::elaborate_predicates(self.tcx, predicates)
-        .filter_map(|predicate| {
-            // we're only interesting in `T : 'a` style predicates:
-            let outlives = match predicate {
-                ty::Predicate::TypeOutlives(data) => data,
-                _ => { return None; }
-            };
-
-            debug!("projection_bounds: outlives={:?} (1)",
-                   outlives);
-
-            // apply the substitutions (and normalize any projected types)
-            let outlives = self.instantiate_type_scheme(span,
-                                                        projection_ty.trait_ref.substs,
-                                                        &outlives);
-
-            debug!("projection_bounds: outlives={:?} (2)",
-                   outlives);
-
-            let region_result = self.commit_if_ok(|_| {
-                let (outlives, _) =
-                    self.replace_late_bound_regions_with_fresh_var(
-                        span,
-                        infer::AssocTypeProjection(projection_ty.item_name),
-                        &outlives);
-
-                debug!("projection_bounds: outlives={:?} (3)",
+                debug!("projection_bounds: outlives={:?} (1)",
                        outlives);
 
-                // check whether this predicate applies to our current projection
-                match self.eq_types(false, TypeOrigin::Misc(span), ty, outlives.0) {
-                    Ok(InferOk { obligations, .. }) => {
-                        // FIXME(#32730) propagate obligations
-                        assert!(obligations.is_empty());
-                        Ok(outlives.1)
+                // apply the substitutions (and normalize any projected types)
+                let outlives = self.instantiate_type_scheme(span,
+                                                            projection_ty.trait_ref.substs,
+                                                            &outlives);
+
+                debug!("projection_bounds: outlives={:?} (2)",
+                       outlives);
+
+                let region_result = self.commit_if_ok(|_| {
+                    let (outlives, _) =
+                        self.replace_late_bound_regions_with_fresh_var(
+                            span,
+                            infer::AssocTypeProjection(projection_ty.item_name),
+                            &outlives);
+
+                    debug!("projection_bounds: outlives={:?} (3)",
+                           outlives);
+
+                    // check whether this predicate applies to our current projection
+                    match self.eq_types(false, TypeOrigin::Misc(span), ty, outlives.0) {
+                        Ok(InferOk { obligations, .. }) => {
+                            // FIXME(#32730) propagate obligations
+                            assert!(obligations.is_empty());
+                            Ok(outlives.1)
+                        }
+                        Err(_) => { Err(()) }
                     }
-                    Err(_) => { Err(()) }
-                }
-            });
+                });
 
-            debug!("projection_bounds: region_result={:?}",
-                   region_result);
+                debug!("projection_bounds: region_result={:?}",
+                       region_result);
 
-            region_result.ok()
-        })
-        .collect()
-}
+                region_result.ok()
+            })
+            .collect()
+    }
 }
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 10c16391bf7..19964d736f5 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -57,29 +57,29 @@ use rustc::hir::intravisit::{self, Visitor};
 // PUBLIC ENTRY POINTS
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-pub fn closure_analyze_fn(&self, body: &hir::Block) {
-    let mut seed = SeedBorrowKind::new(self);
-    seed.visit_block(body);
-    let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
+    pub fn closure_analyze_fn(&self, body: &hir::Block) {
+        let mut seed = SeedBorrowKind::new(self);
+        seed.visit_block(body);
+        let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
 
-    let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds);
-    adjust.visit_block(body);
+        let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds);
+        adjust.visit_block(body);
 
-    // it's our job to process these.
-    assert!(self.deferred_call_resolutions.borrow().is_empty());
-}
+        // it's our job to process these.
+        assert!(self.deferred_call_resolutions.borrow().is_empty());
+    }
 
-pub fn closure_analyze_const(&self, body: &hir::Expr) {
-    let mut seed = SeedBorrowKind::new(self);
-    seed.visit_expr(body);
-    let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
+    pub fn closure_analyze_const(&self, body: &hir::Expr) {
+        let mut seed = SeedBorrowKind::new(self);
+        seed.visit_expr(body);
+        let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
 
-    let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds);
-    adjust.visit_expr(body);
+        let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds);
+        adjust.visit_expr(body);
 
-    // it's our job to process these.
-    assert!(self.deferred_call_resolutions.borrow().is_empty());
-}
+        // it's our job to process these.
+        assert!(self.deferred_call_resolutions.borrow().is_empty());
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -288,7 +288,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                                upvar_id);
 
                         // to move out of an upvar, this must be a FnOnce closure
-                        self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce);
+                        self.adjust_closure_kind(upvar_id.closure_expr_id,
+                                                 ty::ClosureKind::FnOnce);
 
                         let upvar_capture_map =
                             &mut self.fcx.tables.borrow_mut().upvar_capture_map;
@@ -301,7 +302,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                         // must still adjust the kind of the closure
                         // to be a FnOnce closure to permit moves out
                         // of the environment.
-                        self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce);
+                        self.adjust_closure_kind(upvar_id.closure_expr_id,
+                                                 ty::ClosureKind::FnOnce);
                     }
                     mc::NoteNone => {
                     }
@@ -423,9 +425,10 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// We infer the borrow_kind with which to borrow upvars in a stack closure. The borrow_kind
-    /// basically follows a lattice of `imm < unique-imm < mut`, moving from left to right as needed
-    /// (but never right to left). Here the argument `mutbl` is the borrow_kind that is required by
+    /// We infer the borrow_kind with which to borrow upvars in a stack closure.
+    /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`,
+    /// moving from left to right as needed (but never right to left).
+    /// Here the argument `mutbl` is the borrow_kind that is required by
     /// some particular use.
     fn adjust_upvar_borrow_kind(&self,
                                 upvar_id: ty::UpvarId,
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index bb63cf11d9a..e0a34189773 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -576,46 +576,46 @@ struct AdtField<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-fn struct_variant(&self, struct_def: &hir::VariantData) -> AdtVariant<'tcx> {
-    let fields =
-        struct_def.fields().iter()
-        .map(|field| {
-            let field_ty = self.tcx.node_id_to_type(field.id);
-            let field_ty = self.instantiate_type_scheme(field.span,
-                                                        &self.parameter_environment
-                                                             .free_substs,
-                                                        &field_ty);
-            AdtField { ty: field_ty, span: field.span }
-        })
-        .collect();
-    AdtVariant { fields: fields }
-}
+    fn struct_variant(&self, struct_def: &hir::VariantData) -> AdtVariant<'tcx> {
+        let fields =
+            struct_def.fields().iter()
+            .map(|field| {
+                let field_ty = self.tcx.node_id_to_type(field.id);
+                let field_ty = self.instantiate_type_scheme(field.span,
+                                                            &self.parameter_environment
+                                                                 .free_substs,
+                                                            &field_ty);
+                AdtField { ty: field_ty, span: field.span }
+            })
+            .collect();
+        AdtVariant { fields: fields }
+    }
 
-fn enum_variants(&self, enum_def: &hir::EnumDef) -> Vec<AdtVariant<'tcx>> {
-    enum_def.variants.iter()
-        .map(|variant| self.struct_variant(&variant.node.data))
-        .collect()
-}
+    fn enum_variants(&self, enum_def: &hir::EnumDef) -> Vec<AdtVariant<'tcx>> {
+        enum_def.variants.iter()
+            .map(|variant| self.struct_variant(&variant.node.data))
+            .collect()
+    }
 
-fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
-    let free_substs = &self.parameter_environment.free_substs;
-    match self.tcx.impl_trait_ref(impl_def_id) {
-        Some(ref trait_ref) => {
-            // Trait impl: take implied bounds from all types that
-            // appear in the trait reference.
-            let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref);
-            trait_ref.substs.types.as_slice().to_vec()
-        }
+    fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
+        let free_substs = &self.parameter_environment.free_substs;
+        match self.tcx.impl_trait_ref(impl_def_id) {
+            Some(ref trait_ref) => {
+                // Trait impl: take implied bounds from all types that
+                // appear in the trait reference.
+                let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref);
+                trait_ref.substs.types.as_slice().to_vec()
+            }
 
-        None => {
-            // Inherent impl: take implied bounds from the self type.
-            let self_ty = self.tcx.lookup_item_type(impl_def_id).ty;
-            let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty);
-            vec![self_ty]
+            None => {
+                // Inherent impl: take implied bounds from the self type.
+                let self_ty = self.tcx.lookup_item_type(impl_def_id).ty;
+                let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty);
+                vec![self_ty]
+            }
         }
     }
 }
-}
 
 fn error_192(ccx: &CrateCtxt, span: Span) {
     span_err!(ccx.tcx.sess, span, E0192,
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 1c7496d611e..e6500747c05 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -35,35 +35,35 @@ use rustc::hir;
 // Entry point functions
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-pub fn resolve_type_vars_in_expr(&self, e: &hir::Expr) {
-    assert_eq!(self.writeback_errors.get(), false);
-    let mut wbcx = WritebackCx::new(self);
-    wbcx.visit_expr(e);
-    wbcx.visit_upvar_borrow_map();
-    wbcx.visit_closures();
-    wbcx.visit_liberated_fn_sigs();
-    wbcx.visit_fru_field_types();
-}
-
-pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, blk: &hir::Block) {
-    assert_eq!(self.writeback_errors.get(), false);
-    let mut wbcx = WritebackCx::new(self);
-    wbcx.visit_block(blk);
-    for arg in &decl.inputs {
-        wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
-        wbcx.visit_pat(&arg.pat);
-
-        // Privacy needs the type for the whole pattern, not just each binding
-        if !pat_util::pat_is_binding(&self.tcx.def_map.borrow(), &arg.pat) {
-            wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
-                               arg.pat.id);
-        }
+    pub fn resolve_type_vars_in_expr(&self, e: &hir::Expr) {
+        assert_eq!(self.writeback_errors.get(), false);
+        let mut wbcx = WritebackCx::new(self);
+        wbcx.visit_expr(e);
+        wbcx.visit_upvar_borrow_map();
+        wbcx.visit_closures();
+        wbcx.visit_liberated_fn_sigs();
+        wbcx.visit_fru_field_types();
+    }
+
+    pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, blk: &hir::Block) {
+        assert_eq!(self.writeback_errors.get(), false);
+        let mut wbcx = WritebackCx::new(self);
+        wbcx.visit_block(blk);
+        for arg in &decl.inputs {
+            wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
+            wbcx.visit_pat(&arg.pat);
+
+            // Privacy needs the type for the whole pattern, not just each binding
+            if !pat_util::pat_is_binding(&self.tcx.def_map.borrow(), &arg.pat) {
+                wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
+                                   arg.pat.id);
+            }
+        }
+        wbcx.visit_upvar_borrow_map();
+        wbcx.visit_closures();
+        wbcx.visit_liberated_fn_sigs();
+        wbcx.visit_fru_field_types();
     }
-    wbcx.visit_upvar_borrow_map();
-    wbcx.visit_closures();
-    wbcx.visit_liberated_fn_sigs();
-    wbcx.visit_fru_field_types();
-}
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 33238f6cda7..8bee0467f11 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -66,39 +66,39 @@ impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, '
 
 impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
 
-// Returns the def ID of the base type, if there is one.
-fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
-    match ty.sty {
-        TyEnum(def, _) |
-        TyStruct(def, _) => {
-            Some(def.did)
-        }
+    // Returns the def ID of the base type, if there is one.
+    fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
+        match ty.sty {
+            TyEnum(def, _) |
+            TyStruct(def, _) => {
+                Some(def.did)
+            }
 
-        TyTrait(ref t) => {
-            Some(t.principal_def_id())
-        }
+            TyTrait(ref t) => {
+                Some(t.principal_def_id())
+            }
 
-        TyBox(_) => {
-            self.inference_context.tcx.lang_items.owned_box()
-        }
+            TyBox(_) => {
+                self.inference_context.tcx.lang_items.owned_box()
+            }
 
-        TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
-        TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) |
-        TyTuple(..) | TyParam(..) | TyError |
-        TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => {
-            None
-        }
+            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
+            TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) |
+            TyTuple(..) | TyParam(..) | TyError |
+            TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => {
+                None
+            }
 
-        TyInfer(..) | TyClosure(..) => {
-            // `ty` comes from a user declaration so we should only expect types
-            // that the user can type
-            span_bug!(
-                span,
-                "coherence encountered unexpected type searching for base type: {}",
-                ty);
+            TyInfer(..) | TyClosure(..) => {
+                // `ty` comes from a user declaration so we should only expect types
+                // that the user can type
+                span_bug!(
+                    span,
+                    "coherence encountered unexpected type searching for base type: {}",
+                    ty);
+            }
         }
     }
-}
 
     fn check(&self) {
         // Check implementations and traits. This populates the tables