diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs
index 43d99ecb427..edb544aca6d 100644
--- a/src/librustc/middle/infer/coercion.rs
+++ b/src/librustc/middle/infer/coercion.rs
@@ -60,10 +60,9 @@
 //! sort of a minor point so I've opted to leave it for later---after all
 //! we may want to adjust precisely when coercions occur.
 
-use super::{CoerceResult, resolve_type, Coercion};
+use super::{CoerceResult, Coercion};
 use super::combine::{CombineFields, Combine};
 use super::sub::Sub;
-use super::resolve::try_resolve_tvar_shallow;
 
 use middle::subst;
 use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
@@ -197,18 +196,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
     pub fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
         F: FnOnce(&ty::sty<'tcx>) -> T,
     {
-        match resolve_type(self.get_ref().infcx, None,
-                           a, try_resolve_tvar_shallow) {
-            Ok(t) => {
-                f(&t.sty)
-            }
-            Err(e) => {
-                self.get_ref().infcx.tcx.sess.span_bug(
-                    self.get_ref().trace.origin.span(),
-                    format!("failed to resolve even without \
-                             any force options: {}", e).as_slice());
-            }
-        }
+        f(&self.get_ref().infcx.shallow_resolve(a).sty)
     }
 
     // ~T -> &T or &mut T -> &T (including where T = [U] or str)
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 4ad7af713bd..0c70d208119 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -19,13 +19,6 @@ pub use self::TypeOrigin::*;
 pub use self::ValuePairs::*;
 pub use self::fixup_err::*;
 pub use middle::ty::IntVarValue;
-pub use self::resolve::resolve_and_force_all_but_regions;
-pub use self::resolve::{force_all, not_regions};
-pub use self::resolve::{force_ivar};
-pub use self::resolve::{force_tvar, force_rvar};
-pub use self::resolve::{resolve_ivar, resolve_all};
-pub use self::resolve::{resolve_nested_tvar};
-pub use self::resolve::{resolve_rvar};
 pub use self::skolemize::TypeSkolemizer;
 
 use middle::subst;
@@ -47,7 +40,6 @@ use util::ppaux::{trait_ref_to_string, Repr};
 use self::coercion::Coerce;
 use self::combine::{Combine, CombineFields};
 use self::region_inference::{RegionVarBindings, RegionSnapshot};
-use self::resolve::{resolver};
 use self::equate::Equate;
 use self::sub::Sub;
 use self::lub::Lub;
@@ -453,22 +445,6 @@ pub fn mk_coercety<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
     })
 }
 
-// See comment on the type `resolve_state` below
-pub fn resolve_type<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
-                              span: Option<Span>,
-                              a: Ty<'tcx>,
-                              modes: uint)
-                              -> fres<Ty<'tcx>> {
-    let mut resolver = resolver(cx, modes, span);
-    cx.commit_unconditionally(|| resolver.resolve_type_chk(a))
-}
-
-pub fn resolve_region(cx: &InferCtxt, r: ty::Region, modes: uint)
-                      -> fres<ty::Region> {
-    let mut resolver = resolver(cx, modes, None);
-    resolver.resolve_region_chk(r)
-}
-
 trait then<'tcx> {
     fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where
         T: Clone,
@@ -835,20 +811,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         trait_ref_to_string(self.tcx, &t)
     }
 
-    pub fn contains_unbound_type_variables(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
-        match resolve_type(self,
-                           None,
-                           typ, resolve_nested_tvar | resolve_ivar) {
-          Ok(new_type) => new_type,
-          Err(_) => typ
-        }
-    }
-
     pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
         match typ.sty {
             ty::ty_infer(ty::TyVar(v)) => {
+                // Not entirely obvious: if `typ` is a type variable,
+                // it can be resolved to an int/float variable, which
+                // can then be recursively resolved, hence the
+                // recursion. Note though that we prevent type
+                // variables from unifying to other type variables
+                // directly (though they may be embedded
+                // structurally), and we prevent cycles in any case,
+                // so this recursion should always be of very limited
+                // depth.
                 self.type_variables.borrow()
                     .probe(v)
+                    .map(|t| self.shallow_resolve(t))
                     .unwrap_or(typ)
             }
 
@@ -869,10 +846,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn resolve_type_vars_if_possible<T:TypeFoldable<'tcx>>(&self, value: &T) -> T {
-        let mut r = resolve::DeepTypeResolver::new(self);
+        /*!
+         * Where possible, replaces type/int/float variables in
+         * `value` with their final value. Note that region variables
+         * are unaffected. If a type variable has not been unified, it
+         * is left as is.  This is an idempotent operation that does
+         * not affect inference state in any way and so you can do it
+         * at will.
+         */
+
+        let mut r = resolve::OpportunisticTypeResolver::new(self);
         value.fold_with(&mut r)
     }
 
+    pub fn fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> fres<T> {
+        /*!
+         * Attempts to resolve all type/region variables in
+         * `value`. Region inference must have been run already (e.g.,
+         * by calling `resolve_regions_and_report_errors`).  If some
+         * variable was never unified, an `Err` results.
+         *
+         * This method is idempotent, but it not typically not invoked
+         * except during the writeback phase.
+         */
+
+        resolve::fully_resolve(self, value)
+    }
+
     // [Note-Type-error-reporting]
     // An invariant is that anytime the expected or actual type is ty_err (the special
     // error type, meaning that an error occurred when typechecking this expression),
diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs
index 5edf78a474b..12400de31ed 100644
--- a/src/librustc/middle/infer/resolve.rs
+++ b/src/librustc/middle/infer/resolve.rs
@@ -8,276 +8,30 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Resolution is the process of removing type variables and replacing
-// them with their inferred values.  Unfortunately our inference has
-// become fairly complex and so there are a number of options to
-// control *just how much* you want to resolve and how you want to do
-// it.
-//
-// # Controlling the scope of resolution
-//
-// The options resolve_* determine what kinds of variables get
-// resolved.  Generally resolution starts with a top-level type
-// variable; we will always resolve this.  However, once we have
-// resolved that variable, we may end up with a type that still
-// contains type variables.  For example, if we resolve `<T0>` we may
-// end up with something like `[<T1>]`.  If the option
-// `resolve_nested_tvar` is passed, we will then go and recursively
-// resolve `<T1>`.
-//
-// The options `resolve_rvar` controls whether we resolve region
-// variables. The options `resolve_fvar` and `resolve_ivar` control
-// whether we resolve floating point and integral variables,
-// respectively.
-//
-// # What do if things are unconstrained
-//
-// Sometimes we will encounter a variable that has no constraints, and
-// therefore cannot sensibly be mapped to any particular result.  By
-// default, we will leave such variables as is (so you will get back a
-// variable in your result).  The options force_* will cause the
-// resolution to fail in this case instead, except for the case of
-// integral variables, which resolve to `int` if forced.
-//
-// # resolve_all and force_all
-//
-// The options are a bit set, so you can use the *_all to resolve or
-// force all kinds of variables (including those we may add in the
-// future).  If you want to resolve everything but one type, you are
-// probably better off writing `resolve_all - resolve_ivar`.
-
-#![allow(non_upper_case_globals)]
-
-use super::{fixup_err, fres, InferCtxt};
-use super::{unresolved_int_ty,unresolved_float_ty,unresolved_ty};
-
-use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid};
-use middle::ty::{IntType, UintType};
+use super::{InferCtxt, fixup_err, fres, unresolved_ty, unresolved_int_ty, unresolved_float_ty};
 use middle::ty::{mod, Ty};
-use middle::ty_fold;
-use syntax::codemap::Span;
-use util::ppaux::{Repr, ty_to_string};
-
-pub const resolve_nested_tvar: uint = 0b0000000001;
-pub const resolve_rvar: uint        = 0b0000000010;
-pub const resolve_ivar: uint        = 0b0000000100;
-pub const resolve_fvar: uint        = 0b0000001000;
-pub const resolve_all: uint         = 0b0000001111;
-pub const force_tvar: uint          = 0b0000100000;
-pub const force_rvar: uint          = 0b0001000000;
-pub const force_ivar: uint          = 0b0010000000;
-pub const force_fvar: uint          = 0b0100000000;
-pub const force_all: uint           = 0b0111100000;
-
-pub const not_regions: uint         = !(force_rvar | resolve_rvar);
-
-pub const try_resolve_tvar_shallow: uint = 0;
-pub const resolve_and_force_all_but_regions: uint =
-    (resolve_all | force_all) & not_regions;
-
-pub struct ResolveState<'a, 'tcx: 'a> {
-    infcx: &'a InferCtxt<'a, 'tcx>,
-    modes: uint,
-    err: Option<fixup_err>,
-    type_depth: uint,
-}
-
-pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>,
-                          modes: uint,
-                          _: Option<Span>)
-                          -> ResolveState<'a, 'tcx> {
-    ResolveState {
-        infcx: infcx,
-        modes: modes,
-        err: None,
-        type_depth: 0,
-    }
-}
-
-impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for ResolveState<'a, 'tcx> {
-    fn tcx(&self) -> &ty::ctxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        self.resolve_type(t)
-    }
-
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-        self.resolve_region(r)
-    }
-}
-
-impl<'a, 'tcx> ResolveState<'a, 'tcx> {
-    pub fn should(&mut self, mode: uint) -> bool {
-        (self.modes & mode) == mode
-    }
-
-    pub fn resolve_type_chk(&mut self, typ: Ty<'tcx>) -> fres<Ty<'tcx>> {
-        self.err = None;
-
-        debug!("Resolving {} (modes={:x})",
-               ty_to_string(self.infcx.tcx, typ),
-               self.modes);
-
-        // n.b. This is a hokey mess because the current fold doesn't
-        // allow us to pass back errors in any useful way.
-
-        let rty = self.resolve_type(typ);
-        match self.err {
-            None => {
-                debug!("Resolved {} to {} (modes={:x})",
-                       ty_to_string(self.infcx.tcx, typ),
-                       ty_to_string(self.infcx.tcx, rty),
-                       self.modes);
-                return Ok(rty);
-            }
-            Some(e) => {
-                return Err(e);
-            }
-        }
-    }
-
-    pub fn resolve_region_chk(&mut self,
-                              orig: ty::Region)
-                              -> fres<ty::Region> {
-        self.err = None;
-        let resolved = self.resolve_region(orig);
-        match self.err {
-          None => Ok(resolved),
-          Some(e) => Err(e)
-        }
-    }
-
-    pub fn resolve_type(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> {
-        debug!("resolve_type({})", typ.repr(self.infcx.tcx));
-
-        if !ty::type_needs_infer(typ) {
-            return typ;
-        }
-
-        if self.type_depth > 0 && !self.should(resolve_nested_tvar) {
-            return typ;
-        }
-
-        match typ.sty {
-            ty::ty_infer(TyVar(vid)) => {
-                self.resolve_ty_var(vid)
-            }
-            ty::ty_infer(IntVar(vid)) => {
-                self.resolve_int_var(vid)
-            }
-            ty::ty_infer(FloatVar(vid)) => {
-                self.resolve_float_var(vid)
-            }
-            _ => {
-                if self.modes & resolve_all == 0 {
-                    // if we are only resolving top-level type
-                    // variables, and this is not a top-level type
-                    // variable, then shortcircuit for efficiency
-                    typ
-                } else {
-                    self.type_depth += 1;
-                    let result = ty_fold::super_fold_ty(self, typ);
-                    self.type_depth -= 1;
-                    result
-                }
-            }
-        }
-    }
-
-    pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region {
-        debug!("Resolve_region({})", orig.repr(self.infcx.tcx));
-        match orig {
-          ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid),
-          _ => orig
-        }
-    }
-
-    pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region {
-        if !self.should(resolve_rvar) {
-            return ty::ReInfer(ty::ReVar(rid));
-        }
-        self.infcx.region_vars.resolve_var(rid)
-    }
-
-    pub fn resolve_ty_var(&mut self, vid: TyVid) -> Ty<'tcx> {
-        let tcx = self.infcx.tcx;
-        let tv = self.infcx.type_variables.borrow();
-        match tv.probe(vid) {
-            Some(t) => {
-                self.resolve_type(t)
-            }
-            None => {
-                if self.should(force_tvar) {
-                    self.err = Some(unresolved_ty(vid));
-                }
-                ty::mk_var(tcx, vid)
-            }
-        }
-    }
-
-    pub fn resolve_int_var(&mut self, vid: IntVid) -> Ty<'tcx> {
-        if !self.should(resolve_ivar) {
-            return ty::mk_int_var(self.infcx.tcx, vid);
-        }
-
-        let tcx = self.infcx.tcx;
-        let table = &self.infcx.int_unification_table;
-        let node = table.borrow_mut().get(tcx, vid);
-        match node.value {
-          Some(IntType(t)) => ty::mk_mach_int(t),
-          Some(UintType(t)) => ty::mk_mach_uint(t),
-          None => {
-            if self.should(force_ivar) {
-                // As a last resort, emit an error.
-                self.err = Some(unresolved_int_ty(vid));
-            }
-            ty::mk_int_var(self.infcx.tcx, vid)
-          }
-        }
-    }
-
-    pub fn resolve_float_var(&mut self, vid: FloatVid) -> Ty<'tcx> {
-        if !self.should(resolve_fvar) {
-            return ty::mk_float_var(self.infcx.tcx, vid);
-        }
-
-        let tcx = self.infcx.tcx;
-        let table = &self.infcx.float_unification_table;
-        let node = table.borrow_mut().get(tcx, vid);
-        match node.value {
-          Some(t) => ty::mk_mach_float(t),
-          None => {
-            if self.should(force_fvar) {
-                // As a last resort, emit an error.
-                self.err = Some(unresolved_float_ty(vid));
-            }
-            ty::mk_float_var(self.infcx.tcx, vid)
-          }
-        }
-    }
-}
+use middle::ty_fold::{mod, TypeFoldable};
+use util::ppaux::Repr;
 
 ///////////////////////////////////////////////////////////////////////////
-/// DEEP TYPE RESOLVER
-///
-/// This kind of resolver can be used at any time. It simply replaces
+// OPPORTUNISTIC TYPE RESOLVER
+
+/// The opportunistic type resolver can be used at any time. It simply replaces
 /// type variables that have been unified with the things they have
 /// been unified with (similar to `shallow_resolve`, but deep). This is
 /// useful for printing messages etc but also required at various
 /// points for correctness.
-pub struct DeepTypeResolver<'a, 'tcx:'a> {
+pub struct OpportunisticTypeResolver<'a, 'tcx:'a> {
     infcx: &'a InferCtxt<'a, 'tcx>,
 }
 
-impl<'a, 'tcx> DeepTypeResolver<'a, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> DeepTypeResolver<'a, 'tcx> {
-        DeepTypeResolver { infcx: infcx }
+impl<'a, 'tcx> OpportunisticTypeResolver<'a, 'tcx> {
+    pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> OpportunisticTypeResolver<'a, 'tcx> {
+        OpportunisticTypeResolver { infcx: infcx }
     }
 }
 
-impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for DeepTypeResolver<'a, 'tcx> {
+impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> {
     fn tcx(&self) -> &ty::ctxt<'tcx> {
         self.infcx.tcx
     }
@@ -292,4 +46,70 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for DeepTypeResolver<'a, 'tcx> {
     }
 }
 
+///////////////////////////////////////////////////////////////////////////
+// FULL TYPE RESOLUTION
+
+/// Full type resolution replaces all type and region variables with
+/// their concrete results. If any variable cannot be replaced (never unified, etc)
+/// then an `Err` result is returned.
+pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a,'tcx>, value: &T) -> fres<T>
+    where T : TypeFoldable<'tcx>
+{
+    let mut full_resolver = FullTypeResolver { infcx: infcx, err: None };
+    let result = value.fold_with(&mut full_resolver);
+    match full_resolver.err {
+        None => Ok(result),
+        Some(e) => Err(e),
+    }
+}
+
+// N.B. This type is not public because the protocol around checking the
+// `err` field is not enforcable otherwise.
+struct FullTypeResolver<'a, 'tcx:'a> {
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    err: Option<fixup_err>,
+}
+
+impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
+    fn tcx(&self) -> &ty::ctxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        if !ty::type_needs_infer(t) {
+            t // micro-optimize -- if there is nothing in this type that this fold affects...
+        } else {
+            let t = self.infcx.shallow_resolve(t);
+            match t.sty {
+                ty::ty_infer(ty::TyVar(vid)) => {
+                    self.err = Some(unresolved_ty(vid));
+                    ty::mk_err()
+                }
+                ty::ty_infer(ty::IntVar(vid)) => {
+                    self.err = Some(unresolved_int_ty(vid));
+                    ty::mk_err()
+                }
+                ty::ty_infer(ty::FloatVar(vid)) => {
+                    self.err = Some(unresolved_float_ty(vid));
+                    ty::mk_err()
+                }
+                ty::ty_infer(_) => {
+                    self.infcx.tcx.sess.bug(
+                        format!("Unexpected type in full type resolver: {}",
+                                t.repr(self.infcx.tcx))[]);
+                }
+                _ => {
+                    ty_fold::super_fold_ty(self, t)
+                }
+            }
+        }
+    }
+
+    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+        match r {
+          ty::ReInfer(ty::ReVar(rid)) => self.infcx.region_vars.resolve_var(rid),
+          _ => r,
+        }
+    }
+}
 
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index b88da5d9387..b31683219f1 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use middle::def;
-use middle::infer::{mod, resolve};
+use middle::infer;
 use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
 use middle::subst::{Subst, Substs};
 use middle::ty::{mod, Ty};
@@ -143,11 +143,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
         ast::PatRegion(ref inner) => {
             let inner_ty = fcx.infcx().next_ty_var();
 
-            let mutbl = infer::resolve_type(
-                fcx.infcx(), Some(pat.span),
-                expected, resolve::try_resolve_tvar_shallow)
-                .ok()
-                .and_then(|t| ty::deref(t, true))
+            let mutbl =
+                ty::deref(fcx.infcx().shallow_resolve(expected), true)
                 .map_or(ast::MutImmutable, |mt| mt.mutbl);
 
             let mt = ty::mt { ty: inner_ty, mutbl: mutbl };
@@ -214,23 +211,21 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                                       inner: &ast::Pat) -> bool {
     let fcx = pcx.fcx;
     let tcx = pcx.fcx.ccx.tcx;
-    match infer::resolve_type(
-        fcx.infcx(), Some(span),
-        expected, resolve::try_resolve_tvar_shallow) {
-        Ok(t) if pat_is_binding(&tcx.def_map, inner) => {
-            ty::deref(t, true).map_or(true, |mt| match mt.ty.sty {
-                ty::ty_trait(_) => {
-                    // 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",
-                        fcx.infcx().ty_to_string(t));
-                    false
-                }
-                _ => true
-            })
-        }
-        _ => true
+    if pat_is_binding(&tcx.def_map, inner) {
+        let expected = fcx.infcx().shallow_resolve(expected);
+        ty::deref(expected, true).map_or(true, |mt| match mt.ty.sty {
+            ty::ty_trait(_) => {
+                // 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",
+                          fcx.infcx().ty_to_string(expected));
+                false
+            }
+            _ => true
+        })
+    } else {
+        true
     }
 }
 
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 980097eaead..9af9eaf75f5 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -12,8 +12,6 @@
 use check::FnCtxt;
 use middle::ty::{mod, Ty};
 use middle::infer;
-use middle::infer::resolve_type;
-use middle::infer::resolve::try_resolve_tvar_shallow;
 
 use std::result::Result::{Err, Ok};
 use syntax::ast;
@@ -63,12 +61,7 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
     debug!("demand::coerce(expected = {}, expr_ty = {})",
            expected.repr(fcx.ccx.tcx),
            expr_ty.repr(fcx.ccx.tcx));
-    let expected = if ty::type_needs_infer(expected) {
-        resolve_type(fcx.infcx(),
-                     None,
-                     expected,
-                     try_resolve_tvar_shallow).unwrap_or(expected)
-    } else { expected };
+    let expected = fcx.infcx().resolve_type_vars_if_possible(&expected);
     match fcx.mk_assignty(expr, expr_ty, expected) {
       Ok(()) => { /* ok */ }
       Err(ref err) => {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index bfa3c384da7..ad6ba0a1d55 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -124,8 +124,6 @@ use middle::region::CodeExtent;
 use middle::traits;
 use middle::ty::{ReScope};
 use middle::ty::{mod, Ty, MethodCall};
-use middle::infer::resolve_and_force_all_but_regions;
-use middle::infer::resolve_type;
 use middle::infer;
 use middle::pat_util;
 use util::nodemap::{DefIdMap, NodeMap, FnvHashMap};
@@ -307,11 +305,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
     /// of b will be `&<R0>.int` and then `*b` will require that `<R0>` be bigger than the let and
     /// the `*b` expression, so we will effectively resolve `<R0>` to be the block B.
     pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> {
-        match resolve_type(self.fcx.infcx(), None, unresolved_ty,
-                           resolve_and_force_all_but_regions) {
-            Ok(t) => t,
-            Err(_) => ty::mk_err()
-        }
+        self.fcx.infcx().resolve_type_vars_if_possible(&unresolved_ty)
     }
 
     /// Try to resolve the type for the given node.
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 8d94cf5dd5e..b73381966e8 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -19,8 +19,6 @@ use middle::def;
 use middle::pat_util;
 use middle::ty::{mod, Ty, MethodCall, MethodCallee};
 use middle::ty_fold::{TypeFolder,TypeFoldable};
-use middle::infer::{force_all, resolve_all, resolve_region};
-use middle::infer::resolve_type;
 use middle::infer;
 use write_substs_to_tcx;
 use write_ty_to_tcx;
@@ -337,8 +335,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         }
     }
 
-    fn resolve<T:ResolveIn<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
-        t.resolve_in(&mut Resolver::new(self.fcx, reason))
+    fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
+        t.fold_with(&mut Resolver::new(self.fcx, reason))
     }
 }
 
@@ -375,19 +373,6 @@ impl ResolveReason {
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
-// Convenience methods for resolving different kinds of things.
-
-trait ResolveIn<'tcx> {
-    fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> Self;
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> ResolveIn<'tcx> for T {
-    fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> T {
-        self.fold_with(resolver)
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // The Resolver. This is the type folding engine that detects
 // unresolved types and so forth.
@@ -465,13 +450,11 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if !ty::type_needs_infer(t) {
-            return t;
-        }
-
-        match resolve_type(self.infcx, None, t, resolve_all | force_all) {
+        match self.infcx.fully_resolve(&t) {
             Ok(t) => t,
             Err(e) => {
+                debug!("Resolver::fold_ty: input type `{}` not fully resolvable",
+                       t.repr(self.tcx));
                 self.report_error(e);
                 ty::mk_err()
             }
@@ -479,7 +462,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
     }
 
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-        match resolve_region(self.infcx, r, resolve_all | force_all) {
+        match self.infcx.fully_resolve(&r) {
             Ok(r) => r,
             Err(e) => {
                 self.report_error(e);
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index a55f3c61919..8ed0ac98e1e 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -26,12 +26,13 @@ use middle::ty::{ty_param, Polytype, ty_ptr};
 use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
 use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open};
 use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn};
-use middle::ty::{type_is_ty_var};
+use middle::ty::{ty_closure};
+use middle::subst::Subst;
 use middle::ty;
 use CrateCtxt;
 use middle::infer::combine::Combine;
 use middle::infer::InferCtxt;
-use middle::infer::{new_infer_ctxt, resolve_ivar, resolve_type};
+use middle::infer::{new_infer_ctxt};
 use std::collections::{HashSet};
 use std::cell::RefCell;
 use std::rc::Rc;
@@ -52,80 +53,35 @@ mod orphan;
 mod overlap;
 mod unsafety;
 
-fn get_base_type<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
-                           span: Span,
-                           original_type: Ty<'tcx>)
-                           -> Option<Ty<'tcx>> {
-    let resolved_type = match resolve_type(inference_context,
-                                           Some(span),
-                                           original_type,
-                                           resolve_ivar) {
-        Ok(resulting_type) if !type_is_ty_var(resulting_type) => resulting_type,
-        _ => {
-            inference_context.tcx.sess.span_fatal(span,
-                                                  "the type of this value must be known in order \
-                                                   to determine the base type");
-        }
-    };
-
-    match resolved_type.sty {
-        ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => {
-            debug!("(getting base type) found base type");
-            Some(resolved_type)
+// Returns the def ID of the base type, if there is one.
+fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
+                                  span: Span,
+                                  ty: Ty<'tcx>)
+                                  -> Option<DefId> {
+    match ty.sty {
+        ty_enum(def_id, _) |
+        ty_struct(def_id, _) => {
+            Some(def_id)
         }
 
-        _ if ty::type_is_trait(resolved_type) => {
-            debug!("(getting base type) found base type (trait)");
-            Some(resolved_type)
+        ty_trait(ref t) => {
+            Some(t.principal.def_id)
         }
 
         ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
         ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
-        ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) |
+        ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) |
         ty_ptr(_) | ty_rptr(_, _) => {
-            debug!("(getting base type) no base type; found {}",
-                   original_type.sty);
             None
         }
-        ty_trait(..) => panic!("should have been caught")
-    }
-}
 
-// Returns the def ID of the base type, if there is one.
-fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
-                                  span: Span,
-                                  original_type: Ty<'tcx>)
-                                  -> Option<DefId> {
-    match get_base_type(inference_context, span, original_type) {
-        None => None,
-        Some(base_type) => {
-            match base_type.sty {
-                ty_enum(def_id, _) |
-                ty_struct(def_id, _) |
-                ty_unboxed_closure(def_id, _, _) => {
-                    Some(def_id)
-                }
-                ty_ptr(ty::mt {ty, ..}) |
-                ty_rptr(_, ty::mt {ty, ..}) |
-                ty_uniq(ty) => {
-                    match ty.sty {
-                        ty_trait(box ty::TyTrait { ref principal, .. }) => {
-                            Some(principal.def_id)
-                        }
-                        _ => {
-                            panic!("get_base_type() returned a type that wasn't an \
-                                   enum, struct, or trait");
-                        }
-                    }
-                }
-                ty_trait(box ty::TyTrait { ref principal, .. }) => {
-                    Some(principal.def_id)
-                }
-                _ => {
-                    panic!("get_base_type() returned a type that wasn't an \
-                           enum, struct, or trait");
-                }
-            }
+        ty_infer(..) | ty_unboxed_closure(..) => {
+            // `ty` comes from a user declaration so we should only expect types
+            // that the user can type
+            inference_context.tcx.sess.span_bug(
+                span,
+                format!("coherence encountered unexpected type searching for base type: {}",
+                        ty.repr(inference_context.tcx))[]);
         }
     }
 }