about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2015-03-16 18:45:01 +0200
committerNick Cameron <ncameron@mozilla.com>2015-04-14 21:55:42 +1200
commit4e8e64140ff60d1a20d7e54369db714a9fcd8b96 (patch)
tree2b3a26030c79205545f0d66e766a72ecef5f0e70
parenta4eb5a66a5b33b209a1263830d89d83381a42ccb (diff)
downloadrust-4e8e64140ff60d1a20d7e54369db714a9fcd8b96.tar.gz
rust-4e8e64140ff60d1a20d7e54369db714a9fcd8b96.zip
eddyb's refactoring of coercions/adjustments
-rw-r--r--src/librustc/middle/astencode.rs274
-rw-r--r--src/librustc/middle/expr_use_visitor.rs88
-rw-r--r--src/librustc/middle/mem_categorization.rs38
-rw-r--r--src/librustc/middle/ty.rs326
-rw-r--r--src/librustc/middle/ty_fold.rs31
-rw-r--r--src/librustc_lint/builtin.rs4
-rw-r--r--src/librustc_trans/trans/common.rs27
-rw-r--r--src/librustc_trans/trans/consts.rs115
-rw-r--r--src/librustc_trans/trans/expr.rs319
-rw-r--r--src/librustc_trans/trans/type_of.rs4
-rw-r--r--src/librustc_typeck/astconv.rs50
-rw-r--r--src/librustc_typeck/check/callee.rs37
-rw-r--r--src/librustc_typeck/check/coercion.rs395
-rw-r--r--src/librustc_typeck/check/method/confirm.rs133
-rw-r--r--src/librustc_typeck/check/method/mod.rs32
-rw-r--r--src/librustc_typeck/check/method/probe.rs167
-rw-r--r--src/librustc_typeck/check/mod.rs166
-rw-r--r--src/librustc_typeck/check/regionck.rs29
-rw-r--r--src/librustc_typeck/check/vtable.rs38
-rw-r--r--src/librustc_typeck/check/writeback.rs13
-rw-r--r--src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs2
-rw-r--r--src/test/compile-fail/issue-18819.rs2
-rw-r--r--src/test/compile-fail/issue-19482.rs (renamed from src/test/run-pass/issue-19121.rs)7
-rw-r--r--src/test/compile-fail/retslot-cast.rs6
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs2
25 files changed, 815 insertions, 1490 deletions
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 998ce0cac47..2b8540a34b1 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -601,18 +601,18 @@ impl tr for ty::UpvarCapture {
 
 trait read_method_callee_helper<'tcx> {
     fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-        -> (ty::ExprAdjustment, MethodCallee<'tcx>);
+                                  -> (u32, MethodCallee<'tcx>);
 }
 
 fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>,
                                   rbml_w: &mut Encoder,
-                                  adjustment: ty::ExprAdjustment,
+                                  autoderef: u32,
                                   method: &MethodCallee<'tcx>) {
     use serialize::Encoder;
 
     rbml_w.emit_struct("MethodCallee", 4, |rbml_w| {
-        rbml_w.emit_struct_field("adjustment", 0, |rbml_w| {
-            adjustment.encode(rbml_w)
+        rbml_w.emit_struct_field("autoderef", 0, |rbml_w| {
+            autoderef.encode(rbml_w)
         });
         rbml_w.emit_struct_field("origin", 1, |rbml_w| {
             Ok(rbml_w.emit_method_origin(ecx, &method.origin))
@@ -628,13 +628,13 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>,
 
 impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> {
     fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-        -> (ty::ExprAdjustment, MethodCallee<'tcx>) {
+                                  -> (u32, MethodCallee<'tcx>) {
 
         self.read_struct("MethodCallee", 4, |this| {
-            let adjustment = this.read_struct_field("adjustment", 0, |this| {
+            let autoderef = this.read_struct_field("autoderef", 0, |this| {
                 Decodable::decode(this)
             }).unwrap();
-            Ok((adjustment, MethodCallee {
+            Ok((autoderef, MethodCallee {
                 origin: this.read_struct_field("origin", 1, |this| {
                     Ok(this.read_method_origin(dcx))
                 }).unwrap(),
@@ -688,7 +688,7 @@ pub trait vtable_decoder_helpers<'tcx> {
     fn read_vtable_res_with_key(&mut self,
                                 tcx: &ty::ctxt<'tcx>,
                                 cdata: &cstore::crate_metadata)
-                                -> (ty::ExprAdjustment, ty::vtable_res<'tcx>);
+                                -> (u32, ty::vtable_res<'tcx>);
     fn read_vtable_res(&mut self,
                        tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata)
                       -> ty::vtable_res<'tcx>;
@@ -713,12 +713,12 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> {
     fn read_vtable_res_with_key(&mut self,
                                 tcx: &ty::ctxt<'tcx>,
                                 cdata: &cstore::crate_metadata)
-                                -> (ty::ExprAdjustment, ty::vtable_res<'tcx>) {
+                                -> (u32, ty::vtable_res<'tcx>) {
         self.read_struct("VtableWithKey", 2, |this| {
-            let adjustment = this.read_struct_field("adjustment", 0, |this| {
+            let autoderef = this.read_struct_field("autoderef", 0, |this| {
                 Decodable::decode(this)
             }).unwrap();
-            Ok((adjustment, this.read_struct_field("vtable_res", 1, |this| {
+            Ok((autoderef, this.read_struct_field("vtable_res", 1, |this| {
                 Ok(this.read_vtable_res(tcx, cdata))
             }).unwrap()))
         }).unwrap()
@@ -845,12 +845,9 @@ trait rbml_writer_helpers<'tcx> {
     fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds);
     fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                                 adj: &ty::AutoAdjustment<'tcx>);
-    fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                        autoref: &ty::AutoRef<'tcx>);
+    fn emit_autoref<'a>(&mut self, autoref: &ty::AutoRef<'tcx>);
     fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                                auto_deref_ref: &ty::AutoDerefRef<'tcx>);
-    fn emit_unsize_kind<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                            uk: &ty::UnsizeKind<'tcx>);
 }
 
 impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
@@ -1012,10 +1009,8 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
 
         self.emit_enum("AutoAdjustment", |this| {
             match *adj {
-                ty::AdjustReifyFnPointer(def_id) => {
-                    this.emit_enum_variant("AdjustReifyFnPointer", 1, 2, |this| {
-                        this.emit_enum_variant_arg(0, |this| def_id.encode(this))
-                    })
+                ty::AdjustReifyFnPointer=> {
+                    this.emit_enum_variant("AdjustReifyFnPointer", 1, 0, |_| Ok(()))
                 }
 
                 ty::AdjustUnsafeFnPointer => {
@@ -1034,50 +1029,20 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
         });
     }
 
-    fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
-                        autoref: &ty::AutoRef<'tcx>) {
+    fn emit_autoref<'b>(&mut self, autoref: &ty::AutoRef<'tcx>) {
         use serialize::Encoder;
 
         self.emit_enum("AutoRef", |this| {
             match autoref {
-                &ty::AutoPtr(r, m, None) => {
-                    this.emit_enum_variant("AutoPtr", 0, 3, |this| {
-                        this.emit_enum_variant_arg(0, |this| r.encode(this));
-                        this.emit_enum_variant_arg(1, |this| m.encode(this));
-                        this.emit_enum_variant_arg(2,
-                            |this| this.emit_option(|this| this.emit_option_none()))
-                    })
-                }
-                &ty::AutoPtr(r, m, Some(box ref a)) => {
-                    this.emit_enum_variant("AutoPtr", 0, 3, |this| {
+                &ty::AutoPtr(r, m) => {
+                    this.emit_enum_variant("AutoPtr", 0, 2, |this| {
                         this.emit_enum_variant_arg(0, |this| r.encode(this));
-                        this.emit_enum_variant_arg(1, |this| m.encode(this));
-                        this.emit_enum_variant_arg(2, |this| this.emit_option(
-                            |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a)))))
-                    })
-                }
-                &ty::AutoUnsize(ref uk) => {
-                    this.emit_enum_variant("AutoUnsize", 1, 1, |this| {
-                        this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk)))
+                        this.emit_enum_variant_arg(1, |this| m.encode(this))
                     })
                 }
-                &ty::AutoUnsizeUniq(ref uk) => {
-                    this.emit_enum_variant("AutoUnsizeUniq", 2, 1, |this| {
-                        this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk)))
-                    })
-                }
-                &ty::AutoUnsafe(m, None) => {
-                    this.emit_enum_variant("AutoUnsafe", 3, 2, |this| {
-                        this.emit_enum_variant_arg(0, |this| m.encode(this));
-                        this.emit_enum_variant_arg(1,
-                            |this| this.emit_option(|this| this.emit_option_none()))
-                    })
-                }
-                &ty::AutoUnsafe(m, Some(box ref a)) => {
-                    this.emit_enum_variant("AutoUnsafe", 3, 2, |this| {
-                        this.emit_enum_variant_arg(0, |this| m.encode(this));
-                        this.emit_enum_variant_arg(1, |this| this.emit_option(
-                            |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a)))))
+                &ty::AutoUnsafe(m) => {
+                    this.emit_enum_variant("AutoUnsafe", 1, 1, |this| {
+                        this.emit_enum_variant_arg(0, |this| m.encode(this))
                     })
                 }
             }
@@ -1090,55 +1055,26 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
 
         self.emit_struct("AutoDerefRef", 2, |this| {
             this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this));
+
             this.emit_struct_field("autoref", 1, |this| {
                 this.emit_option(|this| {
                     match auto_deref_ref.autoref {
                         None => this.emit_option_none(),
-                        Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))),
+                        Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(a))),
                     }
                 })
-            })
-        });
-    }
-
-    fn emit_unsize_kind<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
-                            uk: &ty::UnsizeKind<'tcx>) {
-        use serialize::Encoder;
+            });
 
-        self.emit_enum("UnsizeKind", |this| {
-            match *uk {
-                ty::UnsizeLength(len) => {
-                    this.emit_enum_variant("UnsizeLength", 0, 1, |this| {
-                        this.emit_enum_variant_arg(0, |this| len.encode(this))
-                    })
-                }
-                ty::UnsizeStruct(box ref uk, idx) => {
-                    this.emit_enum_variant("UnsizeStruct", 1, 2, |this| {
-                        this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk)));
-                        this.emit_enum_variant_arg(1, |this| idx.encode(this))
-                    })
-                }
-                ty::UnsizeVtable(ty::TyTrait { ref principal,
-                                               bounds: ref b },
-                                 self_ty) => {
-                    this.emit_enum_variant("UnsizeVtable", 2, 4, |this| {
-                        this.emit_enum_variant_arg(0, |this| {
-                            try!(this.emit_struct_field("principal", 0, |this| {
-                                Ok(this.emit_trait_ref(ecx, &*principal.0))
-                            }));
-                            this.emit_struct_field("bounds", 1, |this| {
-                                Ok(this.emit_existential_bounds(ecx, b))
-                            })
-                        });
-                        this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty)))
-                    })
-                }
-                ty::UnsizeUpcast(target_ty) => {
-                    this.emit_enum_variant("UnsizeUpcast", 3, 1, |this| {
-                        this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, target_ty)))
-                    })
-                }
-            }
+            this.emit_struct_field("unsize", 2, |this| {
+                this.emit_option(|this| {
+                    match auto_deref_ref.unsize {
+                        None => this.emit_option_none(),
+                        Some(target) => this.emit_option_some(|this| {
+                            Ok(this.emit_ty(ecx, target))
+                        })
+                    }
+                })
+            })
         });
     }
 }
@@ -1258,7 +1194,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
     if let Some(method) = tcx.method_map.borrow().get(&method_call) {
         rbml_w.tag(c::tag_table_method_map, |rbml_w| {
             rbml_w.id(id);
-            encode_method_callee(ecx, rbml_w, method_call.adjustment, method)
+            encode_method_callee(ecx, rbml_w, method_call.autoderef, method)
         })
     }
 
@@ -1271,31 +1207,19 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
 
     if let Some(adjustment) = tcx.adjustments.borrow().get(&id) {
         match *adjustment {
-            _ if ty::adjust_is_object(adjustment) => {
-                let method_call = MethodCall::autoobject(id);
-                if let Some(method) = tcx.method_map.borrow().get(&method_call) {
-                    rbml_w.tag(c::tag_table_method_map, |rbml_w| {
-                        rbml_w.id(id);
-                        encode_method_callee(ecx, rbml_w, method_call.adjustment, method)
-                    })
-                }
-            }
             ty::AdjustDerefRef(ref adj) => {
-                assert!(!ty::adjust_is_object(adjustment));
                 for autoderef in 0..adj.autoderefs {
-                    let method_call = MethodCall::autoderef(id, autoderef);
+                    let method_call = MethodCall::autoderef(id, autoderef as u32);
                     if let Some(method) = tcx.method_map.borrow().get(&method_call) {
                         rbml_w.tag(c::tag_table_method_map, |rbml_w| {
                             rbml_w.id(id);
                             encode_method_callee(ecx, rbml_w,
-                                                 method_call.adjustment, method)
+                                                 method_call.autoderef, method)
                         })
                     }
                 }
             }
-            _ => {
-                assert!(!ty::adjust_is_object(adjustment));
-            }
+            _ => {}
         }
 
         rbml_w.tag(c::tag_table_adjustments, |rbml_w| {
@@ -1367,8 +1291,6 @@ trait rbml_decoder_decoder_helpers<'tcx> {
                                    -> ty::AutoDerefRef<'tcx>;
     fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                             -> ty::AutoRef<'tcx>;
-    fn read_unsize_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                -> ty::UnsizeKind<'tcx>;
     fn convert_def_id(&mut self,
                       dcx: &DecodeContext,
                       source: DefIdSource,
@@ -1640,18 +1562,11 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
     fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
                                     -> ty::AutoAdjustment<'tcx> {
         self.read_enum("AutoAdjustment", |this| {
-            let variants = ["AutoAddEnv", "AutoDerefRef"];
+            let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustDerefRef"];
             this.read_enum_variant(&variants, |this, i| {
                 Ok(match i {
-                    1 => {
-                        let def_id: ast::DefId =
-                            this.read_def_id(dcx);
-
-                        ty::AdjustReifyFnPointer(def_id)
-                    }
-                    2 => {
-                        ty::AdjustUnsafeFnPointer
-                    }
+                    1 => ty::AdjustReifyFnPointer,
+                    2 => ty::AdjustUnsafeFnPointer,
                     3 => {
                         let auto_deref_ref: ty::AutoDerefRef =
                             this.read_enum_variant_arg(0,
@@ -1681,16 +1596,23 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
                         }
                     })
                 }).unwrap(),
+                unsize: this.read_struct_field("unsize", 2, |this| {
+                    this.read_option(|this, b| {
+                        if b {
+                            Ok(Some(this.read_ty(dcx)))
+                        } else {
+                            Ok(None)
+                        }
+                    })
+                }).unwrap(),
             })
         }).unwrap()
     }
 
-    fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::AutoRef<'tcx> {
+    fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
+                            -> ty::AutoRef<'tcx> {
         self.read_enum("AutoRef", |this| {
-            let variants = ["AutoPtr",
-                            "AutoUnsize",
-                            "AutoUnsizeUniq",
-                            "AutoUnsafe"];
+            let variants = ["AutoPtr", "AutoUnsafe"];
             this.read_enum_variant(&variants, |this, i| {
                 Ok(match i {
                     0 => {
@@ -1698,94 +1620,16 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
                             this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
                         let m: ast::Mutability =
                             this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
-                        let a: Option<Box<ty::AutoRef>> =
-                            this.read_enum_variant_arg(2, |this| this.read_option(|this, b| {
-                                if b {
-                                    Ok(Some(box this.read_autoref(dcx)))
-                                } else {
-                                    Ok(None)
-                                }
-                            })).unwrap();
-
-                        ty::AutoPtr(r.tr(dcx), m, a)
-                    }
-                    1 => {
-                        let uk: ty::UnsizeKind =
-                            this.read_enum_variant_arg(0,
-                                |this| Ok(this.read_unsize_kind(dcx))).unwrap();
-
-                        ty::AutoUnsize(uk)
-                    }
-                    2 => {
-                        let uk: ty::UnsizeKind =
-                            this.read_enum_variant_arg(0,
-                                |this| Ok(this.read_unsize_kind(dcx))).unwrap();
 
-                        ty::AutoUnsizeUniq(uk)
+                        ty::AutoPtr(dcx.tcx.mk_region(r.tr(dcx)), m)
                     }
-                    3 => {
+                    1 => {
                         let m: ast::Mutability =
                             this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
-                        let a: Option<Box<ty::AutoRef>> =
-                            this.read_enum_variant_arg(1, |this| this.read_option(|this, b| {
-                                if b {
-                                    Ok(Some(box this.read_autoref(dcx)))
-                                } else {
-                                    Ok(None)
-                                }
-                            })).unwrap();
-
-                        ty::AutoUnsafe(m, a)
-                    }
-                    _ => panic!("bad enum variant for ty::AutoRef")
-                })
-            })
-        }).unwrap()
-    }
-
-    fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                -> ty::UnsizeKind<'tcx> {
-        self.read_enum("UnsizeKind", |this| {
-            let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable", "UnsizeUpcast"];
-            this.read_enum_variant(variants, |this, i| {
-                Ok(match i {
-                    0 => {
-                        let len: usize =
-                            this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
-
-                        ty::UnsizeLength(len)
-                    }
-                    1 => {
-                        let uk: ty::UnsizeKind =
-                            this.read_enum_variant_arg(0,
-                                |this| Ok(this.read_unsize_kind(dcx))).unwrap();
-                        let idx: usize =
-                            this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
 
-                        ty::UnsizeStruct(box uk, idx)
-                    }
-                    2 => {
-                        let ty_trait = try!(this.read_enum_variant_arg(0, |this| {
-                            let principal = try!(this.read_struct_field("principal", 0, |this| {
-                                Ok(this.read_poly_trait_ref(dcx))
-                            }));
-                            Ok(ty::TyTrait {
-                                principal: principal,
-                                bounds: try!(this.read_struct_field("bounds", 1, |this| {
-                                    Ok(this.read_existential_bounds(dcx))
-                                })),
-                            })
-                        }));
-                        let self_ty =
-                            this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap();
-                        ty::UnsizeVtable(ty_trait, self_ty)
+                        ty::AutoUnsafe(m)
                     }
-                    3 => {
-                        let target_ty =
-                            this.read_enum_variant_arg(0, |this| Ok(this.read_ty(dcx))).unwrap();
-                        ty::UnsizeUpcast(target_ty)
-                    }
-                    _ => panic!("bad enum variant for ty::UnsizeKind")
+                    _ => panic!("bad enum variant for ty::AutoRef")
                 })
             })
         }).unwrap()
@@ -1922,10 +1766,10 @@ fn decode_side_tables(dcx: &DecodeContext,
                         dcx.tcx.ty_param_defs.borrow_mut().insert(id, bounds);
                     }
                     c::tag_table_method_map => {
-                        let (adjustment, method) = val_dsr.read_method_callee(dcx);
+                        let (autoderef, method) = val_dsr.read_method_callee(dcx);
                         let method_call = MethodCall {
                             expr_id: id,
-                            adjustment: adjustment
+                            autoderef: autoderef
                         };
                         dcx.tcx.method_map.borrow_mut().insert(method_call, method);
                     }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 18e634a2dd6..c1c551c2be9 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -787,23 +787,30 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     // process.
     fn walk_adjustment(&mut self, expr: &ast::Expr) {
         let typer = self.typer;
-        match typer.adjustments().borrow().get(&expr.id) {
-            None => { }
-            Some(adjustment) => {
-                match *adjustment {
-                    ty::AdjustReifyFnPointer(..) |
-                    ty::AdjustUnsafeFnPointer(..) => {
-                        // Creating a closure/fn-pointer consumes the
-                        // input and stores it into the resulting
-                        // rvalue.
-                        debug!("walk_adjustment(AutoAddEnv|AdjustReifyFnPointer)");
+        if let Some(adjustment) = typer.adjustments().borrow().get(&expr.id) {
+            match *adjustment {
+                ty::AdjustReifyFnPointer |
+                ty::AdjustUnsafeFnPointer => {
+                    // Creating a closure/fn-pointer or unsizing consumes
+                    // the input and stores it into the resulting rvalue.
+                    debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)");
+                    let cmt_unadjusted =
+                        return_if_err!(self.mc.cat_expr_unadjusted(expr));
+                    self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
+                }
+                ty::AdjustDerefRef(ref adj) => {
+                    self.walk_autoderefs(expr, adj.autoderefs);
+                    if let Some(ref r) = adj.autoref {
+                        self.walk_autoref(expr, r, adj.autoderefs);
+                    } else if adj.unsize.is_some() {
+                        assert!(adj.autoderefs == 0,
+                                format!("Expected no derefs with \
+                                         unsize AutoRefs, found: {}",
+                                         adj.repr(self.tcx())));
                         let cmt_unadjusted =
                             return_if_err!(self.mc.cat_expr_unadjusted(expr));
                         self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
                     }
-                    ty::AdjustDerefRef(ref adj) => {
-                        self.walk_autoderefref(expr, adj);
-                    }
                 }
             }
         }
@@ -818,7 +825,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
         debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
 
         for i in 0..autoderefs {
-            let deref_id = ty::MethodCall::autoderef(expr.id, i);
+            let deref_id = ty::MethodCall::autoderef(expr.id, i as u32);
             match self.typer.node_method_ty(deref_id) {
                 None => {}
                 Some(method_ty) => {
@@ -903,59 +910,22 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
             }
         };
 
-        match *autoref {
-            ty::AutoPtr(r, m, ref baseref) => {
-                let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, baseref);
+        let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, baseref);
 
-                debug!("walk_autoref: expr.id={} cmt_base={}",
-                       expr.id,
-                       cmt_base.repr(self.tcx()));
+        debug!("walk_autoref: expr.id={} cmt_base={}",
+               expr.id,
+               cmt_base.repr(self.tcx()));
 
+        match *autoref {
+            ty::AutoPtr(r, m) => {
                 self.delegate.borrow(expr.id,
                                      expr.span,
-                                     cmt_base,
-                                     r,
+                                     cmt_derefd,
+                                     *r,
                                      ty::BorrowKind::from_mutbl(m),
                                      AutoRef);
             }
 
-            ty::AutoUnsize(_) => {
-                // Converting a `[T; N]` to `[T]` or `T` to `Trait`
-                // isn't really a borrow, move, etc, in and of itself.
-                // Also, no recursive step here, this is a base case.
-
-                // It may seem a bit odd to return the cmt_derefd
-                // unmodified here, but in fact I think it's the right
-                // thing to do. Essentially the unsize transformation
-                // isn't really relevant to the borrowing rules --
-                // it's best thought of as a kind of side-modifier to
-                // the autoref, adding additional data that is
-                // attached to the pointer that is produced, but not
-                // affecting the data being borrowed in any other
-                // way. To see what I mean, consider this example:
-                //
-                //    fn foo<'a>(&'a self) -> &'a Trait { self }
-                //
-                // This is valid because the underlying `self` value
-                // lives for the lifetime 'a. If we were to treat the
-                // "unsizing" as e.g. producing an rvalue, that would
-                // only be valid for the temporary scope, which isn't
-                // enough to justify the return value, which have the
-                // lifetime 'a.
-                //
-                // Another option would be to add a variant for
-                // categorization (like downcast) that wraps
-                // cmt_derefd and represents the unsizing operation.
-                // But I don't think there is any particular use for
-                // this (yet). -nmatsakis
-                return cmt_derefd.clone();
-            }
-
-            ty::AutoUnsizeUniq(_) => {
-                // these are handled via special case above
-                self.tcx().sess.span_bug(expr.span, "nexpected AutoUnsizeUniq");
-            }
-
             ty::AutoUnsafe(m, ref baseref) => {
                 let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, baseref);
 
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 6c7dc61109f..003306fe558 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -451,33 +451,23 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
 
             Some(adjustment) => {
                 match *adjustment {
-                    ty::AdjustReifyFnPointer(..) |
-                    ty::AdjustUnsafeFnPointer(..) => {
-                        debug!("cat_expr(AdjustReifyFnPointer): {}",
-                               expr.repr(self.tcx()));
-                        // Convert a bare fn to a closure by adding NULL env.
-                        // Result is an rvalue.
-                        let expr_ty = try!(self.expr_ty_adjusted(expr));
-                        Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
-                    }
-
                     ty::AdjustDerefRef(
                         ty::AutoDerefRef {
-                            autoref: Some(_), ..}) => {
-                        debug!("cat_expr(AdjustDerefRef): {}",
+                            autoref: None, unsize: None, autoderefs, ..}) => {
+                        // Equivalent to *expr or something similar.
+                        self.cat_expr_autoderefd(expr, autoderefs)
+                    }
+
+                    ty::AdjustReifyFnPointer |
+                    ty::AdjustUnsafeFnPointer |
+                    ty::AdjustDerefRef(_) => {
+                        debug!("cat_expr({}): {}",
+                               adjustment.repr(self.tcx()),
                                expr.repr(self.tcx()));
-                        // Equivalent to &*expr or something similar.
                         // Result is an rvalue.
                         let expr_ty = try!(self.expr_ty_adjusted(expr));
                         Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
                     }
-
-                    ty::AdjustDerefRef(
-                        ty::AutoDerefRef {
-                            autoref: None, autoderefs}) => {
-                        // Equivalent to *expr or something similar.
-                        self.cat_expr_autoderefd(expr, autoderefs)
-                    }
                 }
             }
         }
@@ -928,15 +918,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                              deref_cnt: usize,
                              deref_context: DerefKindContext)
                              -> McResult<cmt<'tcx>> {
-        let adjustment = match self.typer.adjustments().borrow().get(&node.id()) {
-            Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject,
-            _ if deref_cnt != 0 => ty::AutoDeref(deref_cnt),
-            _ => ty::NoAdjustment
-        };
-
         let method_call = ty::MethodCall {
             expr_id: node.id(),
-            adjustment: adjustment
+            autoderef: deref_cnt as u32
         };
         let method_ty = self.typer.node_method_ty(method_call);
 
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 0a747ba881f..ccb0fa7bfdb 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -20,7 +20,6 @@ pub use self::ClosureKind::*;
 pub use self::Variance::*;
 pub use self::AutoAdjustment::*;
 pub use self::Representability::*;
-pub use self::UnsizeKind::*;
 pub use self::AutoRef::*;
 pub use self::ExprKind::*;
 pub use self::DtorKind::*;
@@ -33,7 +32,6 @@ pub use self::ImplOrTraitItem::*;
 pub use self::BoundRegion::*;
 pub use self::sty::*;
 pub use self::IntVarValue::*;
-pub use self::ExprAdjustment::*;
 pub use self::vtable_origin::*;
 pub use self::MethodOrigin::*;
 pub use self::CopyImplementationError::*;
@@ -283,145 +281,34 @@ pub enum Variance {
     Bivariant,      // T<A> <: T<B>            -- e.g., unused type parameter
 }
 
-#[derive(Clone, Debug)]
+#[derive(Copy, Clone, Debug)]
 pub enum AutoAdjustment<'tcx> {
-    AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type
+    AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
     AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
-    AdjustDerefRef(AutoDerefRef<'tcx>)
-}
-
-#[derive(Clone, PartialEq, Debug)]
-pub enum UnsizeKind<'tcx> {
-    // [T, ..n] -> [T], the usize field is n.
-    UnsizeLength(usize),
-    // An unsize coercion applied to the tail field of a struct.
-    // The usize is the index of the type parameter which is unsized.
-    UnsizeStruct(Box<UnsizeKind<'tcx>>, usize),
-    UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>),
-    UnsizeUpcast(Ty<'tcx>),
+    AdjustDerefRef(AutoDerefRef<'tcx>),
 }
 
-#[derive(Clone, Debug)]
+#[derive(Copy, Clone, Debug)]
 pub struct AutoDerefRef<'tcx> {
+    /// Apply a number of dereferences, producing an lvalue.
     pub autoderefs: usize,
-    pub autoref: Option<AutoRef<'tcx>>
+
+    /// Produce a pointer/reference from the value.
+    pub autoref: Option<AutoRef<'tcx>>,
+
+    /// Unsize a pointer/reference value, e.g. &[T; n] to &[T].
+    /// The stored type is the target pointer type.
+    pub unsize: Option<Ty<'tcx>>,
 }
 
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub enum AutoRef<'tcx> {
     /// Convert from T to &T
-    /// The third field allows us to wrap other AutoRef adjustments.
-    AutoPtr(Region, ast::Mutability, Option<Box<AutoRef<'tcx>>>),
-
-    /// Convert [T, ..n] to [T] (or similar, depending on the kind)
-    AutoUnsize(UnsizeKind<'tcx>),
-
-    /// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box.
-    /// With DST and Box a library type, this should be replaced by UnsizeStruct.
-    AutoUnsizeUniq(UnsizeKind<'tcx>),
+    AutoPtr(&'tcx Region, ast::Mutability),
 
     /// Convert from T to *T
     /// Value to thin pointer
-    /// The second field allows us to wrap other AutoRef adjustments.
-    AutoUnsafe(ast::Mutability, Option<Box<AutoRef<'tcx>>>),
-}
-
-// Ugly little helper function. The first bool in the returned tuple is true if
-// there is an 'unsize to trait object' adjustment at the bottom of the
-// adjustment. If that is surrounded by an AutoPtr, then we also return the
-// region of the AutoPtr (in the third argument). The second bool is true if the
-// adjustment is unique.
-fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option<Region>) {
-    fn unsize_kind_is_object(k: &UnsizeKind) -> bool {
-        match k {
-            &UnsizeVtable(..) => true,
-            &UnsizeStruct(box ref k, _) => unsize_kind_is_object(k),
-            _ => false
-        }
-    }
-
-    match autoref {
-        &AutoUnsize(ref k) => (unsize_kind_is_object(k), false, None),
-        &AutoUnsizeUniq(ref k) => (unsize_kind_is_object(k), true, None),
-        &AutoPtr(adj_r, _, Some(box ref autoref)) => {
-            let (b, u, r) = autoref_object_region(autoref);
-            if r.is_some() || u {
-                (b, u, r)
-            } else {
-                (b, u, Some(adj_r))
-            }
-        }
-        &AutoUnsafe(_, Some(box ref autoref)) => autoref_object_region(autoref),
-        _ => (false, false, None)
-    }
-}
-
-// If the adjustment introduces a borrowed reference to a trait object, then
-// returns the region of the borrowed reference.
-pub fn adjusted_object_region(adj: &AutoAdjustment) -> Option<Region> {
-    match adj {
-        &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
-            let (b, _, r) = autoref_object_region(autoref);
-            if b {
-                r
-            } else {
-                None
-            }
-        }
-        _ => None
-    }
-}
-
-// Returns true if there is a trait cast at the bottom of the adjustment.
-pub fn adjust_is_object(adj: &AutoAdjustment) -> bool {
-    match adj {
-        &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
-            let (b, _, _) = autoref_object_region(autoref);
-            b
-        }
-        _ => false
-    }
-}
-
-// If possible, returns the type expected from the given adjustment. This is not
-// possible if the adjustment depends on the type of the adjusted expression.
-pub fn type_of_adjust<'tcx>(cx: &ctxt<'tcx>, adj: &AutoAdjustment<'tcx>) -> Option<Ty<'tcx>> {
-    fn type_of_autoref<'tcx>(cx: &ctxt<'tcx>, autoref: &AutoRef<'tcx>) -> Option<Ty<'tcx>> {
-        match autoref {
-            &AutoUnsize(ref k) => match k {
-                &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
-                    Some(mk_trait(cx, principal.clone(), bounds.clone()))
-                }
-                _ => None
-            },
-            &AutoUnsizeUniq(ref k) => match k {
-                &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
-                    Some(mk_uniq(cx, mk_trait(cx, principal.clone(), bounds.clone())))
-                }
-                _ => None
-            },
-            &AutoPtr(r, m, Some(box ref autoref)) => {
-                match type_of_autoref(cx, autoref) {
-                    Some(ty) => Some(mk_rptr(cx, cx.mk_region(r), mt {mutbl: m, ty: ty})),
-                    None => None
-                }
-            }
-            &AutoUnsafe(m, Some(box ref autoref)) => {
-                match type_of_autoref(cx, autoref) {
-                    Some(ty) => Some(mk_ptr(cx, mt {mutbl: m, ty: ty})),
-                    None => None
-                }
-            }
-            _ => None
-        }
-    }
-
-    match adj {
-        &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
-            type_of_autoref(cx, autoref)
-        }
-        _ => None
-    }
+    AutoUnsafe(ast::Mutability),
 }
 
 #[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)]
@@ -509,35 +396,21 @@ pub struct MethodCallee<'tcx> {
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub struct MethodCall {
     pub expr_id: ast::NodeId,
-    pub adjustment: ExprAdjustment
-}
-
-#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy)]
-pub enum ExprAdjustment {
-    NoAdjustment,
-    AutoDeref(usize),
-    AutoObject
+    pub autoderef: u32
 }
 
 impl MethodCall {
     pub fn expr(id: ast::NodeId) -> MethodCall {
         MethodCall {
             expr_id: id,
-            adjustment: NoAdjustment
-        }
-    }
-
-    pub fn autoobject(id: ast::NodeId) -> MethodCall {
-        MethodCall {
-            expr_id: id,
-            adjustment: AutoObject
+            autoderef: 0
         }
     }
 
     pub fn autoderef(expr_id: ast::NodeId, autoderef: usize) -> MethodCall {
         MethodCall {
             expr_id: expr_id,
-            adjustment: AutoDeref(1 + autoderef)
+            autoderef: 1 + autoderef
         }
     }
 }
@@ -4581,16 +4454,15 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
     return match adjustment {
         Some(adjustment) => {
             match *adjustment {
-               AdjustReifyFnPointer(_) => {
+               AdjustReifyFnPointer => {
                     match unadjusted_ty.sty {
                         ty::ty_bare_fn(Some(_), b) => {
                             ty::mk_bare_fn(cx, None, b)
                         }
-                        ref b => {
+                        _ => {
                             cx.sess.bug(
                                 &format!("AdjustReifyFnPointer adjustment on non-fn-item: \
-                                         {:?}",
-                                        b));
+                                          {}", unadjusted_ty.repr(cx)));
                         }
                     }
                 }
@@ -4612,7 +4484,7 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
 
                     if !ty::type_is_error(adjusted_ty) {
                         for i in 0..adj.autoderefs {
-                            let method_call = MethodCall::autoderef(expr_id, i);
+                            let method_call = MethodCall::autoderef(expr_id, i as u32);
                             match method_type(method_call) {
                                 Some(method_ty) => {
                                     // overloaded deref operators have all late-bound
@@ -4639,7 +4511,11 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
                         }
                     }
 
-                    adjust_ty_for_autoref(cx, span, adjusted_ty, adj.autoref.as_ref())
+                    if let Some(target) = adj.unsize {
+                        target
+                    } else {
+                        adjust_ty_for_autoref(cx, adjusted_ty, adj.autoref)
+                    }
                 }
             }
         }
@@ -4648,73 +4524,16 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
 }
 
 pub fn adjust_ty_for_autoref<'tcx>(cx: &ctxt<'tcx>,
-                                   span: Span,
                                    ty: Ty<'tcx>,
-                                   autoref: Option<&AutoRef<'tcx>>)
-                                   -> Ty<'tcx>
-{
+                                   autoref: Option<AutoRef<'tcx>>)
+                                   -> Ty<'tcx> {
     match autoref {
         None => ty,
-
-        Some(&AutoPtr(r, m, ref a)) => {
-            let adjusted_ty = match a {
-                &Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)),
-                &None => ty
-            };
-            mk_rptr(cx, cx.mk_region(r), mt {
-                ty: adjusted_ty,
-                mutbl: m
-            })
+        Some(AutoPtr(r, m)) => {
+            mk_rptr(cx, r, mt { ty: ty, mutbl: m })
         }
-
-        Some(&AutoUnsafe(m, ref a)) => {
-            let adjusted_ty = match a {
-                &Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)),
-                &None => ty
-            };
-            mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m})
-        }
-
-        Some(&AutoUnsize(ref k)) => unsize_ty(cx, ty, k, span),
-
-        Some(&AutoUnsizeUniq(ref k)) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)),
-    }
-}
-
-// Take a sized type and a sizing adjustment and produce an unsized version of
-// the type.
-pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>,
-                       ty: Ty<'tcx>,
-                       kind: &UnsizeKind<'tcx>,
-                       span: Span)
-                       -> Ty<'tcx> {
-    match kind {
-        &UnsizeLength(len) => match ty.sty {
-            ty_vec(ty, Some(n)) => {
-                assert!(len == n);
-                mk_vec(cx, ty, None)
-            }
-            _ => cx.sess.span_bug(span,
-                                  &format!("UnsizeLength with bad sty: {:?}",
-                                          ty_to_string(cx, ty)))
-        },
-        &UnsizeStruct(box ref k, tp_index) => match ty.sty {
-            ty_struct(did, substs) => {
-                let ty_substs = substs.types.get_slice(subst::TypeSpace);
-                let new_ty = unsize_ty(cx, ty_substs[tp_index], k, span);
-                let mut unsized_substs = substs.clone();
-                unsized_substs.types.get_mut_slice(subst::TypeSpace)[tp_index] = new_ty;
-                mk_struct(cx, did, cx.mk_substs(unsized_substs))
-            }
-            _ => cx.sess.span_bug(span,
-                                  &format!("UnsizeStruct with bad sty: {:?}",
-                                          ty_to_string(cx, ty)))
-        },
-        &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
-            mk_trait(cx, principal.clone(), bounds.clone())
-        }
-        &UnsizeUpcast(target_ty) => {
-            target_ty
+        Some(AutoUnsafe(m)) => {
+            mk_ptr(cx, mt { ty: ty, mutbl: m })
         }
     }
 }
@@ -5971,6 +5790,47 @@ pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec<field<'tcx>> {
     }).collect()
 }
 
+/// Returns the deeply last field of nested structures, or the same type,
+/// if not a structure at all. Corresponds to the only possible unsized
+/// field, and its type can be used to determine unsizing strategy.
+pub fn struct_tail<'tcx>(cx: &ctxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> {
+    while let ty_struct(def_id, substs) = ty.sty {
+        match struct_fields(cx, def_id, substs).last() {
+            Some(f) => ty = f.mt.ty,
+            None => break
+        }
+    }
+    ty
+}
+
+/// Same as applying struct_tail on `source` and `target`, but only
+/// keeps going as long as the two types are instances of the same
+/// structure definitions.
+/// For `(Foo<Foo<T>>, Foo<Trait>)`, the result will be `(Foo<T>, Trait)`,
+/// whereas struct_tail produces `T`, and `Trait`, respectively.
+pub fn struct_lockstep_tails<'tcx>(cx: &ctxt<'tcx>,
+                                   source: Ty<'tcx>,
+                                   target: Ty<'tcx>)
+                                   -> (Ty<'tcx>, Ty<'tcx>) {
+    let (mut a, mut b) = (source, target);
+    while let (&ty_struct(a_did, a_substs), &ty_struct(b_did, b_substs)) = (&a.sty, &b.sty) {
+        if a_did != b_did {
+            continue;
+        }
+        if let Some(a_f) = struct_fields(cx, a_did, a_substs).last() {
+            if let Some(b_f) = struct_fields(cx, b_did, b_substs).last() {
+                a = a_f.mt.ty;
+                b = b_f.mt.ty;
+            } else {
+                break;
+            }
+        } else {
+            break;
+        }
+    }
+    (a, b)
+}
+
 #[derive(Copy, Clone)]
 pub struct ClosureUpvar<'tcx> {
     pub def: def::Def,
@@ -6881,8 +6741,8 @@ pub fn with_freevars<T, F>(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where
 impl<'tcx> AutoAdjustment<'tcx> {
     pub fn is_identity(&self) -> bool {
         match *self {
-            AdjustReifyFnPointer(..) => false,
-            AdjustUnsafeFnPointer(..) => false,
+            AdjustReifyFnPointer |
+            AdjustUnsafeFnPointer => false,
             AdjustDerefRef(ref r) => r.is_identity(),
         }
     }
@@ -6890,7 +6750,7 @@ impl<'tcx> AutoAdjustment<'tcx> {
 
 impl<'tcx> AutoDerefRef<'tcx> {
     pub fn is_identity(&self) -> bool {
-        self.autoderefs == 0 && self.autoref.is_none()
+        self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none()
     }
 }
 
@@ -7051,8 +6911,8 @@ impl DebruijnIndex {
 impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> {
     fn repr(&self, tcx: &ctxt<'tcx>) -> String {
         match *self {
-            AdjustReifyFnPointer(def_id) => {
-                format!("AdjustReifyFnPointer({})", def_id.repr(tcx))
+            AdjustReifyFnPointer => {
+                format!("AdjustReifyFnPointer")
             }
             AdjustUnsafeFnPointer => {
                 format!("AdjustUnsafeFnPointer")
@@ -7064,37 +6924,21 @@ impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> {
     }
 }
 
-impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        match *self {
-            UnsizeLength(n) => format!("UnsizeLength({})", n),
-            UnsizeStruct(ref k, n) => format!("UnsizeStruct({},{})", k.repr(tcx), n),
-            UnsizeVtable(ref a, ref b) => format!("UnsizeVtable({},{})", a.repr(tcx), b.repr(tcx)),
-            UnsizeUpcast(ref a) => format!("UnsizeUpcast({})", a.repr(tcx)),
-        }
-    }
-}
-
 impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> {
     fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("AutoDerefRef({}, {})", self.autoderefs, self.autoref.repr(tcx))
+        format!("AutoDerefRef({}, unsize={}, {})",
+                self.autoderefs, self.unsize.repr(tcx), self.autoref.repr(tcx))
     }
 }
 
 impl<'tcx> Repr<'tcx> for AutoRef<'tcx> {
     fn repr(&self, tcx: &ctxt<'tcx>) -> String {
         match *self {
-            AutoPtr(a, b, ref c) => {
-                format!("AutoPtr({},{:?},{})", a.repr(tcx), b, c.repr(tcx))
-            }
-            AutoUnsize(ref a) => {
-                format!("AutoUnsize({})", a.repr(tcx))
-            }
-            AutoUnsizeUniq(ref a) => {
-                format!("AutoUnsizeUniq({})", a.repr(tcx))
+            AutoPtr(a, b) => {
+                format!("AutoPtr({},{:?})", a.repr(tcx), b)
             }
-            AutoUnsafe(ref a, ref b) => {
-                format!("AutoUnsafe({:?},{})", a, b.repr(tcx))
+            AutoUnsafe(ref a) => {
+                format!("AutoUnsafe({:?})", a)
             }
         }
     }
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 5f77574f65e..19a82e3f354 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -477,24 +477,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::UnsizeKind<'tcx> {
-        match *self {
-            ty::UnsizeLength(len) => ty::UnsizeLength(len),
-            ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n),
-            ty::UnsizeVtable(ty::TyTrait{ref principal, ref bounds}, self_ty) => {
-                ty::UnsizeVtable(
-                    ty::TyTrait {
-                        principal: principal.fold_with(folder),
-                        bounds: bounds.fold_with(folder),
-                    },
-                    self_ty.fold_with(folder))
-            }
-            ty::UnsizeUpcast(t) => ty::UnsizeUpcast(t.fold_with(folder)),
-        }
-    }
-}
-
 impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
     where O : TypeFoldable<'tcx>
 {
@@ -768,16 +750,11 @@ pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
                                                      -> ty::AutoRef<'tcx>
 {
     match *autoref {
-        ty::AutoPtr(r, m, None) => ty::AutoPtr(this.fold_region(r), m, None),
-        ty::AutoPtr(r, m, Some(ref a)) => {
-            ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, &**a)))
-        }
-        ty::AutoUnsafe(m, None) => ty::AutoUnsafe(m, None),
-        ty::AutoUnsafe(m, Some(ref a)) => {
-            ty::AutoUnsafe(m, Some(box super_fold_autoref(this, &**a)))
+        ty::AutoPtr(r, m) => {
+            let r = r.fold_with(this);
+            ty::AutoPtr(this.tcx().mk_region(r), m)
         }
-        ty::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)),
-        ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.fold_with(this)),
+        ty::AutoUnsafe(m) => ty::AutoUnsafe(m)
     }
 }
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 3bb737ddc12..c1d71671eb3 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1405,11 +1405,11 @@ impl LintPass for UnusedAllocation {
         if let Some(adjustment) = cx.tcx.adjustments.borrow().get(&e.id) {
             if let ty::AdjustDerefRef(ty::AutoDerefRef { ref autoref, .. }) = *adjustment {
                 match autoref {
-                    &Some(ty::AutoPtr(_, ast::MutImmutable, None)) => {
+                    &Some(ty::AutoPtr(_, ast::MutImmutable)) => {
                         cx.span_lint(UNUSED_ALLOCATION, e.span,
                                      "unnecessary allocation, use & instead");
                     }
-                    &Some(ty::AutoPtr(_, ast::MutMutable, None)) => {
+                    &Some(ty::AutoPtr(_, ast::MutMutable)) => {
                         cx.span_lint(UNUSED_ALLOCATION, e.span,
                                      "unnecessary allocation, use &mut instead");
                     }
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 168a294159d..2ba963a42ef 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -146,33 +146,6 @@ pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
     }
 }
 
-// Return the smallest part of `ty` which is unsized. Fails if `ty` is sized.
-// 'Smallest' here means component of the static representation of the type; not
-// the size of an object at runtime.
-pub fn unsized_part_of_type<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-    match ty.sty {
-        ty::ty_str | ty::ty_trait(..) | ty::ty_vec(..) => ty,
-        ty::ty_struct(def_id, substs) => {
-            let unsized_fields: Vec<_> =
-                ty::struct_fields(cx, def_id, substs)
-                .iter()
-                .map(|f| f.mt.ty)
-                .filter(|ty| !type_is_sized(cx, *ty))
-                .collect();
-
-            // Exactly one of the fields must be unsized.
-            assert!(unsized_fields.len() == 1);
-
-            unsized_part_of_type(cx, unsized_fields[0])
-        }
-        _ => {
-            assert!(type_is_sized(cx, ty),
-                    "unsized_part_of_type failed even though ty is unsized");
-            panic!("called unsized_part_of_type with sized ty");
-        }
-    }
-}
-
 // Some things don't need cleanups during unwinding because the
 // task can free them all at once later. Currently only things
 // that only contain scalars and shared boxes can avoid unwind
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index aff5f597bfd..cd56d196242 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -254,7 +254,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                                             &ty::expr_ty_adjusted(cx.tcx(), e));
     let opt_adj = cx.tcx().adjustments.borrow().get(&e.id).cloned();
     match opt_adj {
-        Some(ty::AdjustReifyFnPointer(_def_id)) => {
+        Some(ty::AdjustReifyFnPointer) => {
             // FIXME(#19925) once fn item types are
             // zero-sized, we'll need to do something here
         }
@@ -272,73 +272,56 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 }
             }
 
-            let second_autoref = match adj.autoref {
-                None => {
-                    let (dv, dt) = const_deref(cx, llconst, ty);
-                    llconst = dv;
-
-                    // If we derefed a fat pointer then we will have an
-                    // open type here. So we need to update the type with
-                    // the one returned from const_deref.
-                    ety_adjusted = dt;
-                    None
-                }
-                Some(ty::AutoUnsafe(_, opt_autoref)) |
-                Some(ty::AutoPtr(_, _, opt_autoref)) => {
-                    if adj.autoderefs == 0 {
-                        // Don't copy data to do a deref+ref
-                        // (i.e., skip the last auto-deref).
-                        llconst = addr_of(cx, llconst, "autoref");
-                    } else {
-                        // Seeing as we are deref'ing here and take a reference
-                        // again to make the pointer part of the far pointer below,
-                        // we just skip the whole thing. We still need the type
-                        // though. This works even if we don't need to deref
-                        // because of byref semantics. Note that this is not just
-                        // an optimisation, it is necessary for mutable vectors to
-                        // work properly.
-                        ty = match ty::deref(ty, true) {
-                            Some(mt) => mt.ty,
-                            None => {
-                                cx.sess().bug(&format!("unexpected dereferenceable type {}",
-                                                       ty_to_string(cx.tcx(), ty)))
-                            }
-                        }
-                    }
-                    opt_autoref
-                }
-                Some(autoref) => {
-                    cx.sess().span_bug(e.span,
-                        &format!("unimplemented const first autoref {:?}", autoref))
-                }
-            };
-            match second_autoref {
-                None => {}
-                Some(box ty::AutoUnsafe(_, None)) |
-                Some(box ty::AutoPtr(_, _, None)) => {
+            if adj.autoref.is_some() {
+                if adj.autoderefs == 0 {
+                    // Don't copy data to do a deref+ref
+                    // (i.e., skip the last auto-deref).
                     llconst = addr_of(cx, llconst, "autoref");
+                    ty = ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ty);
                 }
-                Some(box ty::AutoUnsize(ref k)) => {
-                    let info =
-                        expr::unsized_info(
-                            cx, k, e.id, ty, param_substs,
-                            || const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32]));
-
-                    let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span);
-                    let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
-                    let base = ptrcast(llconst, ptr_ty);
-
-                    let prev_const = cx.const_unsized().borrow_mut()
-                                       .insert(base, llconst);
-                    assert!(prev_const.is_none() || prev_const == Some(llconst));
-                    assert_eq!(abi::FAT_PTR_ADDR, 0);
-                    assert_eq!(abi::FAT_PTR_EXTRA, 1);
-                    llconst = C_struct(cx, &[base, info], false);
-                }
-                Some(autoref) => {
-                    cx.sess().span_bug(e.span,
-                        &format!("unimplemented const second autoref {:?}", autoref))
-                }
+            } else {
+                let (dv, dt) = const_deref(cx, llconst, ty);
+                llconst = dv;
+
+                // If we derefed a fat pointer then we will have an
+                // open type here. So we need to update the type with
+                // the one returned from const_deref.
+                ety_adjusted = dt;
+            }
+
+            if let Some(target) = adj.unsize {
+                let target = monomorphize::apply_param_substs(cx.tcx(),
+                                                              param_substs,
+                                                              &target);
+
+                let pointee_ty = ty::deref(ty, true)
+                    .expect("consts: unsizing got non-pointer type").ty;
+                let (base, old_info) = if !type_is_sized(cx.tcx(), pointee_ty) {
+                    // Normally, the source is a thin pointer and we are
+                    // adding extra info to make a fat pointer. The exception
+                    // is when we are upcasting an existing object fat pointer
+                    // to use a different vtable. In that case, we want to
+                    // load out the original data pointer so we can repackage
+                    // it.
+                    (const_get_elt(cx, llconst, &[abi::FAT_PTR_ADDR as u32]),
+                     Some(const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32])))
+                } else {
+                    (llconst, None)
+                };
+
+                let unsized_ty = ty::deref(target, true)
+                    .expect("consts: unsizing got non-pointer target type").ty;
+                let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
+                let base = ptrcast(base, ptr_ty);
+                let info = expr::unsized_info(cx, pointee_ty, unsized_ty,
+                                              old_info, param_substs);
+
+                let prev_const = cx.const_unsized().borrow_mut()
+                                   .insert(base, llconst);
+                assert!(prev_const.is_none() || prev_const == Some(llconst));
+                assert_eq!(abi::FAT_PTR_ADDR, 0);
+                assert_eq!(abi::FAT_PTR_EXTRA, 1);
+                llconst = C_struct(cx, &[base, info], false);
             }
         }
         None => {}
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 757f3dc1db4..5d9d45e02a9 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -72,8 +72,7 @@ use trans::monomorphize;
 use trans::tvec;
 use trans::type_of;
 use middle::ty::{struct_fields, tup_fields};
-use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer, AutoUnsafe};
-use middle::ty::AutoPtr;
+use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
 use middle::ty::{self, Ty};
 use middle::ty::MethodCall;
 use util::common::indenter;
@@ -290,72 +289,39 @@ pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
     Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr));
 }
 
-// Retrieve the information we are losing (making dynamic) in an unsizing
-// adjustment.
-//
-// The `unadjusted_val` argument is a bit funny. It is intended
-// for use in an upcast, where the new vtable for an object will
-// be drived from the old one. Hence it is a pointer to the fat
-// pointer.
-pub fn unsized_info_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                    kind: &ty::UnsizeKind<'tcx>,
-                                    id: ast::NodeId,
-                                    unadjusted_ty: Ty<'tcx>,
-                                    unadjusted_val: ValueRef, // see above (*)
-                                    param_substs: &'tcx subst::Substs<'tcx>)
-                                    -> ValueRef {
-    unsized_info(
-        bcx.ccx(),
-        kind,
-        id,
-        unadjusted_ty,
-        param_substs,
-        || Load(bcx, GEPi(bcx, unadjusted_val, &[0, abi::FAT_PTR_EXTRA])))
-}
-
-// Same as `unsize_info_bcx`, but does not require a bcx -- instead it
-// takes an extra closure to compute the upcast vtable.
-pub fn unsized_info<'ccx, 'tcx, MK_UPCAST_VTABLE>(
-    ccx: &CrateContext<'ccx, 'tcx>,
-    kind: &ty::UnsizeKind<'tcx>,
-    id: ast::NodeId,
-    unadjusted_ty: Ty<'tcx>,
-    param_substs: &'tcx subst::Substs<'tcx>,
-    mk_upcast_vtable: MK_UPCAST_VTABLE) // see notes above
-    -> ValueRef
-    where MK_UPCAST_VTABLE: FnOnce() -> ValueRef
-{
-    debug!("unsized_info(kind={:?}, id={}, unadjusted_ty={})",
-           kind, id, unadjusted_ty.repr(ccx.tcx()));
-    match kind {
-        &ty::UnsizeLength(len) => C_uint(ccx, len),
-        &ty::UnsizeStruct(box ref k, tp_index) => match unadjusted_ty.sty {
-            ty::ty_struct(_, ref substs) => {
-                let ty_substs = substs.types.get_slice(subst::TypeSpace);
-                unsized_info(ccx, k, id, ty_substs[tp_index], param_substs,
-                             mk_upcast_vtable)
-            }
-            _ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}",
-                                         unadjusted_ty.repr(ccx.tcx())))
-        },
-        &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => {
+/// Retrieve the information we are losing (making dynamic) in an unsizing
+/// adjustment.
+///
+/// The `old_info` argument is a bit funny. It is intended for use
+/// in an upcast, where the new vtable for an object will be drived
+/// from the old one.
+pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
+                                source: Ty<'tcx>,
+                                target: Ty<'tcx>,
+                                old_info: Option<ValueRef>,
+                                param_substs: &'tcx subst::Substs<'tcx>)
+                                -> ValueRef {
+    let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target);
+    match (&source.sty, &target.sty) {
+        (&ty::ty_vec(_, Some(len)), &ty::ty_vec(_, None)) => C_uint(ccx, len),
+        (&ty::ty_trait(_), &ty::ty_trait(_)) => {
+            // For now, upcasts are limited to changes in marker
+            // traits, and hence never actually require an actual
+            // change to the vtable.
+            old_info.expect("unsized_info: missing old info for trait upcast")
+        }
+        (_, &ty::ty_trait(box ty::TyTrait { ref principal, .. })) => {
             // Note that we preserve binding levels here:
-            let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions();
+            let substs = principal.0.substs.with_self_ty(source).erase_regions();
             let substs = ccx.tcx().mk_substs(substs);
             let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(),
-                                                             substs: substs }));
-            let trait_ref = monomorphize::apply_param_substs(ccx.tcx(),
-                                                             param_substs,
-                                                             &trait_ref);
+                                                               substs: substs }));
             consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
                             Type::vtable_ptr(ccx))
         }
-        &ty::UnsizeUpcast(_) => {
-            // For now, upcasts are limited to changes in marker
-            // traits, and hence never actually require an actual
-            // change to the vtable.
-            mk_upcast_vtable()
-        }
+        _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {} -> {}",
+                                     source.repr(ccx.tcx()),
+                                     target.repr(ccx.tcx())))
     }
 }
 
@@ -379,7 +345,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
            datum.to_string(bcx.ccx()),
            adjustment);
     match adjustment {
-        AdjustReifyFnPointer(_def_id) => {
+        AdjustReifyFnPointer => {
             // FIXME(#19925) once fn item types are
             // zero-sized, we'll need to do something here
         }
@@ -387,202 +353,112 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             // purely a type-level thing
         }
         AdjustDerefRef(ref adj) => {
-            let (autoderefs, use_autoref) = match adj.autoref {
-                // Extracting a value from a box counts as a deref, but if we are
-                // just converting Box<[T, ..n]> to Box<[T]> we aren't really doing
-                // a deref (and wouldn't if we could treat Box like a normal struct).
-                Some(ty::AutoUnsizeUniq(..)) => (adj.autoderefs - 1, true),
+            let skip_reborrows = if adj.autoderefs == 1 && adj.autoref.is_some() {
                 // We are a bit paranoid about adjustments and thus might have a re-
                 // borrow here which merely derefs and then refs again (it might have
-                // a different region or mutability, but we don't care here. It might
-                // also be just in case we need to unsize. But if there are no nested
-                // adjustments then it should be a no-op).
-                Some(ty::AutoPtr(_, _, None)) |
-                Some(ty::AutoUnsafe(_, None)) if adj.autoderefs == 1 => {
-                    match datum.ty.sty {
-                        // Don't skip a conversion from Box<T> to &T, etc.
-                        ty::ty_rptr(..) => {
-                            let method_call = MethodCall::autoderef(expr.id, adj.autoderefs-1);
-                            let method = bcx.tcx().method_map.borrow().get(&method_call).is_some();
-                            if method {
-                                // Don't skip an overloaded deref.
-                                (adj.autoderefs, true)
-                            } else {
-                                (adj.autoderefs - 1, false)
-                            }
+                // a different region or mutability, but we don't care here).
+                match datum.ty.sty {
+                    // Don't skip a conversion from Box<T> to &T, etc.
+                    ty::ty_rptr(..) => {
+                        let method_call = MethodCall::autoderef(expr.id, 0);
+                        if bcx.tcx().method_map.borrow().contains_key(&method_call) {
+                            // Don't skip an overloaded deref.
+                            0
+                        } else {
+                            1
                         }
-                        _ => (adj.autoderefs, true),
                     }
+                    _ => 0
                 }
-                _ => (adj.autoderefs, true)
+            } else {
+                0
             };
 
-            if autoderefs > 0 {
+            if adj.autoderefs > skip_reborrows {
                 // Schedule cleanup.
                 let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id));
-                datum = unpack_datum!(
-                    bcx, deref_multiple(bcx, expr, lval.to_expr_datum(), autoderefs));
+                datum = unpack_datum!(bcx, deref_multiple(bcx, expr,
+                                                          lval.to_expr_datum(),
+                                                          adj.autoderefs - skip_reborrows));
             }
 
             // (You might think there is a more elegant way to do this than a
-            // use_autoref bool, but then you remember that the borrow checker exists).
-            if let (true, &Some(ref a)) = (use_autoref, &adj.autoref) {
-                datum = unpack_datum!(bcx, apply_autoref(a,
-                                                         bcx,
-                                                         expr,
-                                                         datum));
+            // skip_reborrows bool, but then you remember that the borrow checker exists).
+            if skip_reborrows == 0 && adj.autoref.is_some() {
+                datum = unpack_datum!(bcx, apply_autoref(bcx, expr, datum));
+            }
+
+            if let Some(target) = adj.unsize {
+                datum = unpack_datum!(bcx, unsize_pointer(bcx, datum,
+                                                          bcx.monomorphize(&target)));
             }
         }
     }
     debug!("after adjustments, datum={}", datum.to_string(bcx.ccx()));
     return DatumBlock::new(bcx, datum);
 
-    fn apply_autoref<'blk, 'tcx>(autoref: &ty::AutoRef<'tcx>,
-                                 bcx: Block<'blk, 'tcx>,
+    fn apply_autoref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  expr: &ast::Expr,
                                  datum: Datum<'tcx, Expr>)
                                  -> DatumBlock<'blk, 'tcx, Expr> {
         let mut bcx = bcx;
-        let mut datum = datum;
-
-        let datum = match autoref {
-            &AutoPtr(_, _, ref a) | &AutoUnsafe(_, ref a) => {
-                debug!("  AutoPtr");
-                if let &Some(box ref a) = a {
-                    datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum));
-                }
-                if !type_is_sized(bcx.tcx(), datum.ty) {
-                    // Arrange cleanup
-                    let lval = unpack_datum!(bcx,
-                        datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id));
-                    unpack_datum!(bcx, ref_fat_ptr(bcx, lval))
-                } else {
-                    unpack_datum!(bcx, auto_ref(bcx, datum, expr))
-                }
-            }
-            &ty::AutoUnsize(ref k) => {
-                debug!("  AutoUnsize");
-                unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k))
-            }
-            &ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => {
-                debug!("  AutoUnsizeUniq(UnsizeLength)");
-                unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len))
-            }
-            &ty::AutoUnsizeUniq(ref k) => {
-                debug!("  AutoUnsizeUniq");
-                unpack_datum!(bcx, unsize_unique_expr(bcx, expr, datum, k))
-            }
-        };
 
-        DatumBlock::new(bcx, datum)
+        if !type_is_sized(bcx.tcx(), datum.ty) {
+            // Arrange cleanup
+            let lval = unpack_datum!(bcx,
+                datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id));
+            ref_fat_ptr(bcx, lval)
+        } else {
+            auto_ref(bcx, datum, expr)
+        }
     }
 
-    fn unsize_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               expr: &ast::Expr,
-                               datum: Datum<'tcx, Expr>,
-                               k: &ty::UnsizeKind<'tcx>)
-                               -> DatumBlock<'blk, 'tcx, Expr> {
+    fn unsize_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                  datum: Datum<'tcx, Expr>,
+                                  target: Ty<'tcx>)
+                                  -> DatumBlock<'blk, 'tcx, Expr> {
         let mut bcx = bcx;
-        let tcx = bcx.tcx();
-        let datum_ty = datum.ty;
-        let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span);
-        debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx()));
-
-        let info = unsized_info_bcx(bcx, k, expr.id, datum_ty, datum.val, bcx.fcx.param_substs);
-
-        // Arrange cleanup
-        let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id));
+        let unsized_ty = ty::deref(target, true)
+            .expect("expr::unsize got non-pointer target type").ty;
+        debug!("unsize_lvalue(unsized_ty={})", unsized_ty.repr(bcx.tcx()));
 
-        // Compute the base pointer. This doesn't change the pointer value,
-        // but merely its type.
-        let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to();
-        let base = if !type_is_sized(bcx.tcx(), lval.ty) {
+        // We do not arrange cleanup ourselves; if we already are an
+        // L-value, then cleanup will have already been scheduled (and
+        // the `datum.to_rvalue_datum` call below will emit code to zero
+        // the drop flag when moving out of the L-value). If we are an
+        // R-value, then we do not need to schedule cleanup.
+        let datum = unpack_datum!(bcx, datum.to_rvalue_datum(bcx, "__unsize_ref"));
+
+        let pointee_ty = ty::deref(datum.ty, true)
+            .expect("expr::unsize got non-pointer datum type").ty;
+        let (base, old_info) = if !type_is_sized(bcx.tcx(), pointee_ty) {
             // Normally, the source is a thin pointer and we are
             // adding extra info to make a fat pointer. The exception
             // is when we are upcasting an existing object fat pointer
             // to use a different vtable. In that case, we want to
             // load out the original data pointer so we can repackage
             // it.
-            Load(bcx, get_dataptr(bcx, lval.val))
+            (Load(bcx, get_dataptr(bcx, datum.val)),
+             Some(Load(bcx, get_len(bcx, datum.val))))
         } else {
-            lval.val
+            (datum.val, None)
         };
+
+        let info = unsized_info(bcx.ccx(), pointee_ty, unsized_ty,
+                                old_info, bcx.fcx.param_substs);
+
+        // Compute the base pointer. This doesn't change the pointer value,
+        // but merely its type.
+        let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to();
         let base = PointerCast(bcx, base, ptr_ty);
 
-        let llty = type_of::type_of(bcx.ccx(), unsized_ty);
+        let llty = type_of::type_of(bcx.ccx(), target);
         // HACK(eddyb) get around issues with lifetime intrinsics.
         let scratch = alloca_no_lifetime(bcx, llty, "__fat_ptr");
         Store(bcx, base, get_dataptr(bcx, scratch));
         Store(bcx, info, get_len(bcx, scratch));
 
-        DatumBlock::new(bcx, Datum::new(scratch, unsized_ty, LvalueExpr))
-    }
-
-    fn unsize_unique_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                     expr: &ast::Expr,
-                                     datum: Datum<'tcx, Expr>,
-                                     len: usize)
-                                     -> DatumBlock<'blk, 'tcx, Expr> {
-        let mut bcx = bcx;
-        let tcx = bcx.tcx();
-
-        let datum_ty = datum.ty;
-
-        debug!("unsize_unique_vec expr.id={} datum_ty={} len={}",
-               expr.id, datum_ty.repr(tcx), len);
-
-        // We do not arrange cleanup ourselves; if we already are an
-        // L-value, then cleanup will have already been scheduled (and
-        // the `datum.store_to` call below will emit code to zero the
-        // drop flag when moving out of the L-value). If we are an R-value,
-        // then we do not need to schedule cleanup.
-
-        let ll_len = C_uint(bcx.ccx(), len);
-        let unit_ty = ty::sequence_element_type(tcx, ty::type_content(datum_ty));
-        let vec_ty = ty::mk_uniq(tcx, ty::mk_vec(tcx, unit_ty, None));
-        let scratch = rvalue_scratch_datum(bcx, vec_ty, "__unsize_unique");
-
-        let base = get_dataptr(bcx, scratch.val);
-        let base = PointerCast(bcx,
-                               base,
-                               type_of::type_of(bcx.ccx(), datum_ty).ptr_to());
-        bcx = datum.store_to(bcx, base);
-
-        Store(bcx, ll_len, get_len(bcx, scratch.val));
-        DatumBlock::new(bcx, scratch.to_expr_datum())
-    }
-
-    fn unsize_unique_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                      expr: &ast::Expr,
-                                      datum: Datum<'tcx, Expr>,
-                                      k: &ty::UnsizeKind<'tcx>)
-                                      -> DatumBlock<'blk, 'tcx, Expr> {
-        let mut bcx = bcx;
-        let tcx = bcx.tcx();
-
-        let datum_ty = datum.ty;
-        let unboxed_ty = match datum_ty.sty {
-            ty::ty_uniq(t) => t,
-            _ => bcx.sess().bug(&format!("Expected ty_uniq, found {}",
-                                        bcx.ty_to_string(datum_ty)))
-        };
-        let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span));
-
-        // We do not arrange cleanup ourselves; if we already are an
-        // L-value, then cleanup will have already been scheduled (and
-        // the `datum.store_to` call below will emit code to zero the
-        // drop flag when moving out of the L-value). If we are an R-value,
-        // then we do not need to schedule cleanup.
-
-        let scratch = rvalue_scratch_datum(bcx, result_ty, "__uniq_fat_ptr");
-        let llbox_ty = type_of::type_of(bcx.ccx(), datum_ty);
-        let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to());
-        bcx = datum.store_to(bcx, base);
-
-        let info = unsized_info_bcx(bcx, k, expr.id, unboxed_ty, base, bcx.fcx.param_substs);
-        Store(bcx, info, get_len(bcx, scratch.val));
-
-        DatumBlock::new(bcx, scratch.to_expr_datum())
+        DatumBlock::new(bcx, Datum::new(scratch, target, RvalueExpr(Rvalue::new(ByRef))))
     }
 }
 
@@ -2233,7 +2109,7 @@ fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let mut bcx = bcx;
     let mut datum = datum;
     for i in 0..times {
-        let method_call = MethodCall::autoderef(expr.id, i);
+        let method_call = MethodCall::autoderef(expr.id, i as u32);
         datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
     }
     DatumBlock { bcx: bcx, datum: datum }
@@ -2265,10 +2141,11 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             // converts from the `Smaht<T>` pointer that we have into
             // a `&T` pointer.  We can then proceed down the normal
             // path (below) to dereference that `&T`.
-            let datum = match method_call.adjustment {
+            let datum = if method_call.autoderef == 0 {
+                datum
+            } else {
                 // Always perform an AutoPtr when applying an overloaded auto-deref
-                ty::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)),
-                _ => datum
+                unpack_datum!(bcx, auto_ref(bcx, datum, expr))
             };
 
             let ref_ty = // invoked methods have their LB regions instantiated
diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs
index 2e577a0bd19..8257dab20fa 100644
--- a/src/librustc_trans/trans/type_of.rs
+++ b/src/librustc_trans/trans/type_of.rs
@@ -359,14 +359,14 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
                   cx.tn().find_type("str_slice").unwrap()
               } else {
                   let ptr_ty = in_memory_type_of(cx, ty).ptr_to();
-                  let unsized_part = unsized_part_of_type(cx.tcx(), ty);
+                  let unsized_part = ty::struct_tail(cx.tcx(), ty);
                   let info_ty = match unsized_part.sty {
                       ty::ty_str | ty::ty_vec(..) => {
                           Type::uint_from_ty(cx, ast::TyUs)
                       }
                       ty::ty_trait(_) => Type::vtable_ptr(cx),
                       _ => panic!("Unexpected type returned from \
-                                   unsized_part_of_type: {} for ty={}",
+                                   struct_tail: {} for ty={}",
                                   unsized_part.repr(cx.tcx()), ty.repr(cx.tcx()))
                   };
                   Type::struct_(cx, &[ptr_ty, info_ty], false)
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 355b866013b..ff22127fdc6 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -59,6 +59,7 @@ use middle::ty::{self, RegionEscape, Ty};
 use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope,
              ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
+use util::nodemap::FnvHashSet;
 use util::ppaux::{self, Repr, UserString};
 
 use std::iter::repeat;
@@ -1011,13 +1012,58 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
                                                      projection_bounds,
                                                      bounds);
 
-    let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds);
+    let result = make_object_type(this, span, trait_ref, existential_bounds);
     debug!("trait_ref_to_object_type: result={}",
            result.repr(this.tcx()));
 
     result
 }
 
+fn make_object_type<'tcx>(this: &AstConv<'tcx>,
+                          span: Span,
+                          principal: ty::PolyTraitRef<'tcx>,
+                          bounds: ty::ExistentialBounds<'tcx>)
+                          -> Ty<'tcx> {
+    let tcx = this.tcx();
+    let object = ty::TyTrait {
+        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 this.ensure_super_predicates(span, object.principal_def_id()).is_err() {
+        return tcx.types.err;
+    }
+
+    let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
+        traits::supertraits(tcx, object_trait_ref)
+        .flat_map(|tr| {
+            let trait_def = ty::lookup_trait_def(tcx, 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.user_string(tcx),
+                    ty::item_path_str(tcx, trait_def_id));
+    }
+
+    ty::mk_trait(tcx, object.principal, object.bounds)
+}
+
 fn report_ambiguous_associated_type(tcx: &ty::ctxt,
                                     span: Span,
                                     type_str: &str,
@@ -1914,7 +1960,7 @@ fn conv_ty_poly_trait_ref<'tcx>(
                                                         projection_bounds,
                                                         partitioned_bounds);
 
-    ty::mk_trait(this.tcx(), main_trait_bound, bounds)
+    make_object_type(this, span, main_trait_bound, bounds)
 }
 
 pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index f54c0b7f8c4..b065eb2d274 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -125,14 +125,10 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
            adjusted_ty.repr(fcx.tcx()),
            autoderefs);
 
-    let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, autoref: None };
-
     // If the callee is a bare function or a closure, then we're all set.
     match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
         ty::ty_bare_fn(..) => {
-            fcx.write_adjustment(callee_expr.id,
-                                 callee_expr.span,
-                                 ty::AdjustDerefRef(autoderefref));
+            fcx.write_autoderef_adjustment(callee_expr.id, autoderefs);
             return Some(CallStep::Builtin);
         }
 
@@ -149,14 +145,14 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
                                                                           infer::FnCall,
                                                                           &closure_ty.sig).0;
-                fcx.record_deferred_call_resolution(
-                    def_id,
-                    Box::new(CallResolution {call_expr: call_expr,
-                                         callee_expr: callee_expr,
-                                         adjusted_ty: adjusted_ty,
-                                         autoderefref: autoderefref,
-                                         fn_sig: fn_sig.clone(),
-                                         closure_def_id: def_id}));
+                fcx.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));
             }
         }
@@ -176,7 +172,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         _ => {}
     }
 
-    try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefref)
+    try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefs)
         .map(|method_callee| CallStep::Overloaded(method_callee))
 }
 
@@ -184,7 +180,7 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                        call_expr: &ast::Expr,
                                        callee_expr: &ast::Expr,
                                        adjusted_ty: Ty<'tcx>,
-                                       autoderefref: ty::AutoDerefRef<'tcx>)
+                                       autoderefs: usize)
                                        -> Option<ty::MethodCallee<'tcx>>
 {
     // Try the options that are least restrictive on the caller first.
@@ -203,7 +199,8 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                                Some(&*callee_expr),
                                                method_name,
                                                trait_def_id,
-                                               autoderefref.clone(),
+                                               autoderefs,
+                                               false,
                                                adjusted_ty,
                                                None) {
             None => continue,
@@ -335,7 +332,7 @@ struct CallResolution<'tcx> {
     call_expr: &'tcx ast::Expr,
     callee_expr: &'tcx ast::Expr,
     adjusted_ty: Ty<'tcx>,
-    autoderefref: ty::AutoDerefRef<'tcx>,
+    autoderefs: usize,
     fn_sig: ty::FnSig<'tcx>,
     closure_def_id: ast::DefId,
 }
@@ -343,11 +340,11 @@ struct CallResolution<'tcx> {
 impl<'tcx> Repr<'tcx> for CallResolution<'tcx> {
     fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
         format!("CallResolution(call_expr={}, callee_expr={}, adjusted_ty={}, \
-                autoderefref={}, fn_sig={}, closure_def_id={})",
+                autoderefs={}, fn_sig={}, closure_def_id={})",
                 self.call_expr.repr(tcx),
                 self.callee_expr.repr(tcx),
                 self.adjusted_ty.repr(tcx),
-                self.autoderefref.repr(tcx),
+                self.autoderefs,
                 self.fn_sig.repr(tcx),
                 self.closure_def_id.repr(tcx))
     }
@@ -364,7 +361,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
 
         // We may now know enough to figure out fn vs fnmut etc.
         match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
-                                         self.adjusted_ty, self.autoderefref.clone()) {
+                                         self.adjusted_ty, self.autoderefs) {
             Some(method_callee) => {
                 // One problem is that when we get here, we are going
                 // to have a newly instantiated function signature
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index ced6cec3ef0..acdeda3d546 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -61,21 +61,26 @@
 //! we may want to adjust precisely when coercions occur.
 
 use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
+use check::vtable;
 
 use middle::infer::{self, Coercion};
 use middle::subst;
-use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
+use middle::traits;
+use middle::ty::{AutoDerefRef, AdjustDerefRef};
 use middle::ty::{self, mt, Ty};
 use middle::ty_relate::RelateResult;
 use util::common::indent;
 use util::ppaux;
 use util::ppaux::Repr;
 
+use std::cell::Cell;
 use syntax::ast;
 
 struct Coerce<'a, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     origin: infer::TypeOrigin,
+    trace: TypeTrace<'tcx>,
+    unsizing_obligation: Cell<Option<Ty<'tcx>>>
 }
 
 type CoerceResult<'tcx> = RelateResult<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
@@ -144,11 +149,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         self.unpack_actual_value(a, |a| {
             match a.sty {
-                ty::ty_bare_fn(Some(a_def_id), a_f) => {
+                ty::ty_bare_fn(Some(_), a_f) => {
                     // Function items are coercible to any closure
                     // type; function pointers are not (that would
                     // require double indirection).
-                    self.coerce_from_fn_item(a, a_def_id, a_f, b)
+                    self.coerce_from_fn_item(a, a_f, b)
                 }
                 ty::ty_bare_fn(None, a_f) => {
                     // We permit coercion of fn pointers to drop the
@@ -184,18 +189,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         match a.sty {
             ty::ty_rptr(_, mt_a) => {
-                if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
-                    return Err(ty::terr_mutability);
-                }
+                try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
             }
             _ => return self.subtype(a, b)
         }
 
         let coercion = Coercion(self.origin.span());
         let r_borrow = self.fcx.infcx().next_region_var(coercion);
-        let autoref = Some(AutoPtr(r_borrow, mutbl_b, None));
-
         let r_borrow = self.tcx().mk_region(r_borrow);
+        let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b));
+
         let lvalue_pref = match mutbl_b {
             ast::MutMutable => PreferMutLvalue,
             ast::MutImmutable => NoPreference
@@ -229,7 +232,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             Some(_) => {
                 Ok(Some(AdjustDerefRef(AutoDerefRef {
                     autoderefs: autoderefs,
-                    autoref: autoref
+                    autoref: autoref,
+                    unsize: None
                 })))
             }
             None => {
@@ -257,183 +261,148 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // we can't unify [T] with U. But to properly support DST, we need to allow
         // that, at which point we will need extra checks on b here.
 
-        match (&a.sty, &b.sty) {
-            (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
-                match self.unsize_ty(t_a, mt_b.ty) {
-                    Some((ty, kind)) => {
-                        if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
-                            return Err(ty::terr_mutability);
-                        }
-
-                        let coercion = Coercion(self.origin.span());
-                        let r_borrow = self.fcx.infcx().next_region_var(coercion);
-                        let ty = ty::mk_rptr(self.tcx(),
-                                             self.tcx().mk_region(r_borrow),
-                                             ty::mt{ty: ty, mutbl: mt_b.mutbl});
-                        try!(self.subtype(ty, b));
-                        debug!("Success, coerced with AutoDerefRef(1, \
-                                AutoPtr(AutoUnsize({:?})))", kind);
-                        Ok(Some(AdjustDerefRef(AutoDerefRef {
-                            autoderefs: 1,
-                            autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
-                                                      Some(box AutoUnsize(kind))))
-                        })))
-                    }
-                    _ => Err(ty::terr_mismatch)
+        let (reborrow, target) = match (&a.sty, &b.sty) {
+            (&ty::ty_rptr(_, mt_a), &ty::ty_rptr(_, mt_b)) => {
+                if let Some(target) = self.unsize_ty(mt_a.ty, mt_b.ty) {
+                    try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
+
+                    let coercion = Coercion(self.trace.clone());
+                    let r_borrow = self.fcx.infcx().next_region_var(coercion);
+                    let region = self.tcx().mk_region(r_borrow);
+                    (Some(ty::AutoPtr(region, mt_b.mutbl)), target)
+                } else {
+                    return Err(ty::terr_mismatch);
                 }
             }
-            (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
-                match self.unsize_ty(t_a, mt_b.ty) {
-                    Some((ty, kind)) => {
-                        if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
-                            return Err(ty::terr_mutability);
-                        }
-
-                        let ty = ty::mk_ptr(self.tcx(),
-                                             ty::mt{ty: ty, mutbl: mt_b.mutbl});
-                        try!(self.subtype(ty, b));
-                        debug!("Success, coerced with AutoDerefRef(1, \
-                                AutoPtr(AutoUnsize({:?})))", kind);
-                        Ok(Some(AdjustDerefRef(AutoDerefRef {
-                            autoderefs: 1,
-                            autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
-                                                         Some(box AutoUnsize(kind))))
-                        })))
-                    }
-                    _ => Err(ty::terr_mismatch)
+            (&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) => {
+                if let Some(target) = self.unsize_ty(mt_a.ty, mt_b.ty) {
+                    try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
+                    (Some(ty::AutoUnsafe(mt_b.mutbl)), target)
+                } else {
+                    return Err(ty::terr_mismatch);
                 }
             }
             (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
-                match self.unsize_ty(t_a, t_b) {
-                    Some((ty, kind)) => {
-                        let ty = ty::mk_uniq(self.tcx(), ty);
-                        try!(self.subtype(ty, b));
-                        debug!("Success, coerced with AutoDerefRef(1, \
-                                AutoUnsizeUniq({:?}))", kind);
-                        Ok(Some(AdjustDerefRef(AutoDerefRef {
-                            autoderefs: 1,
-                            autoref: Some(ty::AutoUnsizeUniq(kind))
-                        })))
-                    }
-                    _ => Err(ty::terr_mismatch)
+                if let Some(target) = self.unsize_ty(t_a, t_b) {
+                    (None, ty::mk_uniq(self.tcx(), target))
+                } else {
+                    return Err(ty::terr_mismatch);
                 }
             }
-            _ => Err(ty::terr_mismatch)
-        }
+            _ => return Err(ty::terr_mismatch)
+        };
+
+        let target = ty::adjust_ty_for_autoref(self.tcx(), target, reborrow);
+        try!(self.fcx.infcx().try(|_| self.subtype(target, b)));
+        let adjustment = AutoDerefRef {
+            autoderefs: if reborrow.is_some() { 1 } else { 0 },
+            autoref: reborrow,
+            unsize: Some(target)
+        };
+        debug!("Success, coerced with {}", adjustment.repr(self.tcx()));
+        Ok(Some(AdjustDerefRef(adjustment)))
     }
 
-    // Takes a type and returns an unsized version along with the adjustment
-    // performed to unsize it.
-    // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
+    // Takes a type and returns an unsized version.
+    // E.g., `[T, ..n]` -> `[T]`.
     fn unsize_ty(&self,
                  ty_a: Ty<'tcx>,
                  ty_b: Ty<'tcx>)
-                 -> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)>
-    {
+                 -> Option<Ty<'tcx>> {
         let tcx = self.tcx();
 
-        self.unpack_actual_value(ty_a, |a| {
-            self.unpack_actual_value(ty_b, |b| {
-                debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx()));
-                match (&a.sty, &b.sty) {
-                    (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
-                        let ty = ty::mk_vec(tcx, t_a, None);
-                        Some((ty, ty::UnsizeLength(len)))
-                    }
-                    (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
-                        // Upcasts permit two things:
-                        //
-                        // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
-                        // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
-                        //
-                        // Note that neither of these changes requires any
-                        // change at runtime.  Eventually this will be
-                        // generalized.
-                        //
-                        // We always upcast when we can because of reason
-                        // #2 (region bounds).
-                        if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
-                            // construct a type `a1` which is a version of
-                            // `a` using the upcast bounds from `b`
-                            let bounds_a1 = ty::ExistentialBounds {
-                                // From type b
-                                region_bound: data_b.bounds.region_bound,
-                                builtin_bounds: data_b.bounds.builtin_bounds,
-
-                                // From type a
-                                projection_bounds: data_a.bounds.projection_bounds.clone(),
-                            };
-                            let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
-
-                            // relate `a1` to `b`
-                            let result = self.fcx.infcx().commit_if_ok(|_| {
-                                // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
-                                try!(self.outlives(infer::RelateObjectBound(self.origin.span()),
-                                                   data_a.bounds.region_bound,
-                                                   data_b.bounds.region_bound));
-                                self.subtype(ty_a1, ty_b)
-                            });
-
-                            // if that was successful, we have a coercion
-                            match result {
-                                Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))),
-                                Err(_) => None,
-                            }
-                        } else {
-                            None
+        self.unpack_actual_value(ty_a, |a| self.unpack_actual_value(ty_b, |b| {
+            debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx()));
+            match (&a.sty, &b.sty) {
+                (&ty::ty_vec(t_a, Some(_)), &ty::ty_vec(_, None)) => {
+                    Some(ty::mk_vec(tcx, t_a, None))
+                }
+                (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
+                    // Upcasts permit two things:
+                    //
+                    // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
+                    // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
+                    //
+                    // Note that neither of these changes requires any
+                    // change at runtime.  Eventually this will be
+                    // generalized.
+                    //
+                    // We always upcast when we can because of reason
+                    // #2 (region bounds).
+                    if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
+                        // construct a type `a1` which is a version of
+                        // `a` using the upcast bounds from `b`
+                        let bounds_a1 = ty::ExistentialBounds {
+                            // From type b
+                            region_bound: data_b.bounds.region_bound,
+                            builtin_bounds: data_b.bounds.builtin_bounds,
+
+                            // From type a
+                            projection_bounds: data_a.bounds.projection_bounds.clone(),
+                        };
+                        let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
+
+                        // relate `a1` to `b`
+                        let result = self.fcx.infcx().commit_if_ok(|_| {
+                            // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
+                            try!(self.outlives(infer::RelateObjectBound(self.origin.span()),
+                                               data_a.bounds.region_bound,
+                                               data_b.bounds.region_bound));
+                            self.subtype(ty_a1, ty_b)
+                        });
+
+                        // if that was successful, we have a coercion
+                        match result {
+                            Ok(_) => Some(ty_b),
+                            Err(_) => None,
                         }
+                    } else {
+                        None
                     }
-                    (_, &ty::ty_trait(ref data)) => {
-                        Some((ty_b, ty::UnsizeVtable(ty::TyTrait {
-                                                         principal: data.principal.clone(),
-                                                         bounds: data.bounds.clone()
-                                                     },
-                                                     ty_a)))
-                    }
-                    (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
-                      if did_a == did_b => {
-                        debug!("unsizing a struct");
-                        // Try unsizing each type param in turn to see if we end up with ty_b.
-                        let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
-                        let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
-                        assert!(ty_substs_a.len() == ty_substs_b.len());
-
-                        let mut result = None;
-                        let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
-                        for (i, (tp_a, tp_b)) in tps {
-                            if self.subtype(*tp_a, *tp_b).is_ok() {
-                                continue;
-                            }
-                            match self.unsize_ty(*tp_a, *tp_b) {
-                                Some((new_tp, k)) => {
-                                    // Check that the whole types match.
-                                    let mut new_substs = substs_a.clone();
-                                    new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
-                                    let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
-                                    if self.subtype(ty, ty_b).is_err() {
-                                        debug!("Unsized type parameter '{}', but still \
-                                                could not match types {} and {}",
-                                               ppaux::ty_to_string(tcx, *tp_a),
-                                               ppaux::ty_to_string(tcx, ty),
-                                               ppaux::ty_to_string(tcx, ty_b));
-                                        // We can only unsize a single type parameter, so
-                                        // if we unsize one and it doesn't give us the
-                                        // type we want, then we won't succeed later.
-                                        break;
-                                    }
-
-                                    result = Some((ty, ty::UnsizeStruct(box k, i)));
-                                    break;
-                                }
-                                None => {}
+                }
+                (_, &ty::ty_trait(_)) => {
+                    assert!(self.unsizing_obligation.get().is_none());
+                    self.unsizing_obligation.set(Some(a));
+                    Some(ty_b)
+                }
+                (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
+                  if did_a == did_b => {
+                    debug!("unsizing a struct");
+                    // Try unsizing each type param in turn to see if we end up with ty_b.
+                    let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
+                    let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
+                    assert!(ty_substs_a.len() == ty_substs_b.len());
+
+                    let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
+                    for (i, (&tp_a, &tp_b)) in tps {
+                        if self.subtype(*tp_a, *tp_b).is_ok() {
+                            continue;
+                        }
+                        if let Some(new_tp) = self.unsize_ty(tp_a, tp_b) {
+                            // Check that the whole types match.
+                            let mut new_substs = substs_a.clone();
+                            new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
+                            let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
+                            if self.subtype(ty, ty_b).is_err() {
+                                debug!("Unsized type parameter '{}', but still \
+                                        could not match types {} and {}",
+                                        ppaux::ty_to_string(tcx, tp_a),
+                                        ppaux::ty_to_string(tcx, ty),
+                                        ppaux::ty_to_string(tcx, ty_b));
+                                // We can only unsize a single type parameter, so
+                                // if we unsize one and it doesn't give us the
+                                // type we want, then we won't succeed later.
+                                break;
                             }
+
+                            return Some(ty);
                         }
-                        result
                     }
-                    _ => None
+                    None
                 }
-            })
-        })
+                _ => None
+            }
+        }))
     }
 
     fn coerce_from_fn_pointer(&self,
@@ -451,29 +420,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             debug!("coerce_from_fn_pointer(a={}, b={})",
                    a.repr(self.tcx()), b.repr(self.tcx()));
 
-            match b.sty {
-                ty::ty_bare_fn(None, fn_ty_b) => {
-                    match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
-                        (ast::Unsafety::Normal, ast::Unsafety::Unsafe) => {
-                            let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
-                            try!(self.subtype(unsafe_a, b));
-                            Ok(Some(ty::AdjustUnsafeFnPointer))
-                        }
-                        _ => {
-                            self.subtype(a, b)
-                        }
+            if let ty::ty_bare_fn(None, fn_ty_b) = b.sty {
+                match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
+                    (ast::Unsafety::Normal, ast::Unsafety::Unsafe) => {
+                        let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
+                        try!(self.subtype(unsafe_a, b));
+                        return Ok(Some(ty::AdjustUnsafeFnPointer));
                     }
-                }
-                _ => {
-                    return self.subtype(a, b)
+                    _ => {}
                 }
             }
+            self.subtype(a, b)
         })
     }
 
     fn coerce_from_fn_item(&self,
                            a: Ty<'tcx>,
-                           fn_def_id_a: ast::DefId,
                            fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
                            b: Ty<'tcx>)
                            -> CoerceResult<'tcx> {
@@ -490,11 +452,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 ty::ty_bare_fn(None, _) => {
                     let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a);
                     try!(self.subtype(a_fn_pointer, b));
-                    Ok(Some(ty::AdjustReifyFnPointer(fn_def_id_a)))
-                }
-                _ => {
-                    return self.subtype(a, b)
+                    Ok(Some(ty::AdjustReifyFnPointer))
                 }
+                _ => self.subtype(a, b)
             }
         })
     }
@@ -518,16 +478,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // Check that the types which they point at are compatible.
         let a_unsafe = ty::mk_ptr(self.tcx(), ty::mt{ mutbl: mutbl_b, ty: mt_a.ty });
         try!(self.subtype(a_unsafe, b));
-        if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
-            return Err(ty::terr_mutability);
-        }
+        try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
 
         // Although references and unsafe ptrs have the same
         // representation, we still register an AutoDerefRef so that
         // regionck knows that the region for `a` must be valid here.
         Ok(Some(AdjustDerefRef(AutoDerefRef {
             autoderefs: 1,
-            autoref: Some(ty::AutoUnsafe(mutbl_b, None))
+            autoref: Some(ty::AutoUnsafe(mutbl_b)),
+            unsize: None
         })))
     }
 }
@@ -538,27 +497,61 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                              b: Ty<'tcx>)
                              -> RelateResult<'tcx, ()> {
     debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
-    let adjustment = try!(indent(|| {
-        fcx.infcx().commit_if_ok(|_| {
-            Coerce {
+    let (adjustment, unsizing_obligation) = try!(indent(|| {
+        fcx.infcx().commit_if_ok(|| {
+            let origin = infer::ExprAssignable(expr.span);
+            let coerce = Coerce {
                 fcx: fcx,
                 origin: infer::ExprAssignable(expr.span),
-            }.coerce(expr, a, b)
+                trace: infer::TypeTrace::types(origin, false, a, b),
+                unsizing_obligation: Cell::new(None)
+            };
+            Ok((try!(coerce.coerce(expr, a, b)),
+                coerce.unsizing_obligation.get()))
         })
     }));
+
+    if let Some(AdjustDerefRef(auto)) = adjustment {
+        if let (Some(source), Some(target)) = (unsizing_obligation, auto.unsize) {
+            let target = ty::deref(target, true)
+                            .expect("coercion: unsizing got non-pointer target type").ty;
+            let target = ty::struct_tail(fcx.tcx(), target);
+            if let ty::ty_trait(ref ty_trait) = target.sty {
+                vtable::check_object_safety(fcx.tcx(), ty_trait, expr.span);
+
+                // If the type is `Foo+'a`, ensures that the type
+                // being cast to `Foo+'a` implements `Foo`:
+                vtable::register_object_cast_obligations(fcx,
+                                                         expr.span,
+                                                         ty_trait,
+                                                         source);
+
+                // If the type is `Foo+'a`, ensures that the type
+                // being cast to `Foo+'a` outlives `'a`:
+                let cause = traits::ObligationCause {
+                    span: expr.span,
+                    body_id: fcx.body_id,
+                    code: traits::ObjectCastObligation(source)
+                };
+                fcx.register_region_obligation(source, ty_trait.bounds.region_bound, cause);
+            }
+        }
+    }
+
     if let Some(adjustment) = adjustment {
-        fcx.write_adjustment(expr.id, expr.span, adjustment);
+        debug!("Success, coerced with {}", adjustment.repr(fcx.tcx()));
+        fcx.write_adjustment(expr.id, adjustment);
     }
     Ok(())
 }
 
-fn can_coerce_mutbls(from_mutbl: ast::Mutability,
-                     to_mutbl: ast::Mutability)
-                     -> bool {
+fn coerce_mutbls<'tcx>(from_mutbl: ast::Mutability,
+                       to_mutbl: ast::Mutability)
+                       -> CoerceResult<'tcx> {
     match (from_mutbl, to_mutbl) {
-        (ast::MutMutable, ast::MutMutable) => true,
-        (ast::MutImmutable, ast::MutImmutable) => true,
-        (ast::MutMutable, ast::MutImmutable) => true,
-        (ast::MutImmutable, ast::MutMutable) => false,
+        (ast::MutMutable, ast::MutMutable) |
+        (ast::MutImmutable, ast::MutImmutable) |
+        (ast::MutMutable, ast::MutImmutable) => Ok(None),
+        (ast::MutImmutable, ast::MutMutable) => Err(ty::terr_mutability)
     }
 }
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 6aefcf5a47c..4e62542854f 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -24,7 +24,6 @@ use middle::infer::InferCtxt;
 use syntax::ast;
 use syntax::codemap::Span;
 use std::rc::Rc;
-use std::mem;
 use std::iter::repeat;
 use util::ppaux::Repr;
 
@@ -84,7 +83,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                -> MethodCallee<'tcx>
     {
         // Adjust the self expression the user provided and obtain the adjusted type.
-        let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment);
+        let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
 
         // Make sure nobody calls `drop()` explicitly.
         self.enforce_illegal_method_limitations(&pick);
@@ -134,11 +133,20 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
 
     fn adjust_self_ty(&mut self,
                       unadjusted_self_ty: Ty<'tcx>,
-                      adjustment: &probe::PickAdjustment)
+                      pick: &probe::Pick<'tcx>)
                       -> Ty<'tcx>
     {
-        // Construct the actual adjustment and write it into the table
-        let auto_deref_ref = self.create_ty_adjustment(adjustment);
+        let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
+            let region = self.infcx().next_region_var(infer::Autoref(self.span));
+            let autoref = ty::AutoPtr(self.tcx().mk_region(region), mutbl);
+            (Some(autoref), pick.unsize.map(|target| {
+                ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref))
+            }))
+        } else {
+            // No unsizing should be performed without autoref.
+            assert!(pick.unsize.is_none());
+            (None, None)
+        };
 
         // Commit the autoderefs by calling `autoderef again, but this
         // time writing the results into the various tables.
@@ -149,47 +157,27 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                                                           UnresolvedTypeAction::Error,
                                                           NoPreference,
                                                           |_, n| {
-            if n == auto_deref_ref.autoderefs {
+            if n == pick.autoderefs {
                 Some(())
             } else {
                 None
             }
         });
-        assert_eq!(n, auto_deref_ref.autoderefs);
+        assert_eq!(n, pick.autoderefs);
         assert_eq!(result, Some(()));
 
-        let final_ty =
-            ty::adjust_ty_for_autoref(self.tcx(), self.span, autoderefd_ty,
-                                      auto_deref_ref.autoref.as_ref());
-
         // Write out the final adjustment.
-        self.fcx.write_adjustment(self.self_expr.id, self.span, ty::AdjustDerefRef(auto_deref_ref));
-
-        final_ty
-    }
+        self.fcx.write_adjustment(self.self_expr.id,
+                                  ty::AdjustDerefRef(ty::AutoDerefRef {
+            autoderefs: pick.autoderefs,
+            autoref: autoref,
+            unsize: unsize
+        }));
 
-    fn create_ty_adjustment(&mut self,
-                            adjustment: &probe::PickAdjustment)
-                            -> ty::AutoDerefRef<'tcx>
-    {
-        match *adjustment {
-            probe::AutoDeref(num) => {
-                ty::AutoDerefRef {
-                    autoderefs: num,
-                    autoref: None,
-                }
-            }
-            probe::AutoUnsizeLength(autoderefs, len) => {
-                ty::AutoDerefRef {
-                    autoderefs: autoderefs,
-                    autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len))),
-                }
-            }
-            probe::AutoRef(mutability, ref sub_adjustment) => {
-                let deref = self.create_ty_adjustment(&**sub_adjustment);
-                let region = self.infcx().next_region_var(infer::Autoref(self.span));
-                wrap_autoref(deref, |base| ty::AutoPtr(region, mutability, base))
-            }
+        if let Some(target) = unsize {
+            target
+        } else {
+            ty::adjust_ty_for_autoref(self.tcx(), autoderefd_ty, autoref)
         }
     }
 
@@ -499,10 +487,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                                             .adjustments
                                             .borrow()
                                             .get(&expr.id) {
-                Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
-                    autoderefs: autoderef_count,
-                    autoref: _
-                })) => autoderef_count,
+                Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs,
                 Some(_) | None => 0,
             };
 
@@ -529,17 +514,6 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
             if i != 0 {
                 match expr.node {
                     ast::ExprIndex(ref base_expr, ref index_expr) => {
-                        let mut base_adjustment =
-                            match self.fcx.inh.adjustments.borrow().get(&base_expr.id) {
-                                Some(&ty::AdjustDerefRef(ref adr)) => (*adr).clone(),
-                                None => ty::AutoDerefRef { autoderefs: 0, autoref: None },
-                                Some(_) => {
-                                    self.tcx().sess.span_bug(
-                                        base_expr.span,
-                                        "unexpected adjustment type");
-                                }
-                            };
-
                         // If this is an overloaded index, the
                         // adjustment will include an extra layer of
                         // autoref because the method is an &self/&mut
@@ -548,21 +522,44 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                         // expects. This is annoying and horrible. We
                         // ought to recode this routine so it doesn't
                         // (ab)use the normal type checking paths.
-                        base_adjustment.autoref = match base_adjustment.autoref {
-                            None => { None }
-                            Some(ty::AutoPtr(_, _, None)) => { None }
-                            Some(ty::AutoPtr(_, _, Some(box r))) => { Some(r) }
+                        let adj = self.fcx.inh.adjustments.borrow().get(&base_expr.id).cloned();
+                        let (autoderefs, unsize) = match adj {
+                            Some(ty::AdjustDerefRef(adr)) => match adr.autoref {
+                                None => {
+                                    assert!(adr.unsize.is_none());
+                                    (adr.autoderefs, None)
+                                }
+                                Some(ty::AutoPtr(_, _)) => {
+                                    (adr.autoderefs, adr.unsize.map(|target| {
+                                        ty::deref(target, false)
+                                            .expect("fixup: AutoPtr is not &T").ty
+                                    }))
+                                }
+                                Some(_) => {
+                                    self.tcx().sess.span_bug(
+                                        base_expr.span,
+                                        &format!("unexpected adjustment autoref {}",
+                                                adr.repr(self.tcx())));
+                                }
+                            },
+                            None => (0, None),
                             Some(_) => {
                                 self.tcx().sess.span_bug(
                                     base_expr.span,
-                                    "unexpected adjustment autoref");
+                                    "unexpected adjustment type");
                             }
                         };
 
-                        let adjusted_base_ty =
-                            self.fcx.adjust_expr_ty(
-                                &**base_expr,
-                                Some(&ty::AdjustDerefRef(base_adjustment.clone())));
+                        let (adjusted_base_ty, unsize) = if let Some(target) = unsize {
+                            (target, true)
+                        } else {
+                            (self.fcx.adjust_expr_ty(base_expr,
+                                Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
+                                    autoderefs: autoderefs,
+                                    autoref: None,
+                                    unsize: None
+                                }))), false)
+                        };
                         let index_expr_ty = self.fcx.expr_ty(&**index_expr);
 
                         let result = check::try_index_step(
@@ -571,7 +568,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                             expr,
                             &**base_expr,
                             adjusted_base_ty,
-                            base_adjustment,
+                            autoderefs,
+                            unsize,
                             PreferMutLvalue,
                             index_expr_ty);
 
@@ -658,14 +656,3 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
             self.span, infer::FnCall, value).0
     }
 }
-
-fn wrap_autoref<'tcx, F>(mut deref: ty::AutoDerefRef<'tcx>,
-                         base_fn: F)
-                         -> ty::AutoDerefRef<'tcx> where
-    F: FnOnce(Option<Box<ty::AutoRef<'tcx>>>) -> ty::AutoRef<'tcx>,
-{
-    let autoref = mem::replace(&mut deref.autoref, None);
-    let autoref = autoref.map(|r| box r);
-    deref.autoref = Some(base_fn(autoref));
-    deref
-}
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 677ab568524..f1a4dbf7cd5 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -122,8 +122,7 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                  -> Option<MethodCallee<'tcx>>
 {
     lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id,
-                             ty::AutoDerefRef { autoderefs: 0, autoref: None },
-                             self_ty, opt_input_types)
+                             0, false, self_ty, opt_input_types)
 }
 
 /// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of
@@ -140,7 +139,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                           self_expr: Option<&ast::Expr>,
                                           m_name: ast::Name,
                                           trait_def_id: DefId,
-                                          autoderefref: ty::AutoDerefRef<'tcx>,
+                                          autoderefs: usize,
+                                          unsize: bool,
                                           self_ty: Ty<'tcx>,
                                           opt_input_types: Option<Vec<Ty<'tcx>>>)
                                           -> Option<MethodCallee<'tcx>>
@@ -241,18 +241,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
         Some(self_expr) => {
             debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
-                   (self-id={}, base adjustment={:?}, explicit_self={:?})",
-                   self_expr.id, autoderefref, method_ty.explicit_self);
+                   (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})",
+                   self_expr.id, autoderefs, unsize,
+                   method_ty.explicit_self);
 
             match method_ty.explicit_self {
                 ty::ByValueExplicitSelfCategory => {
                     // Trait method is fn(self), no transformation needed.
-                    if !autoderefref.is_identity() {
-                        fcx.write_adjustment(
-                            self_expr.id,
-                            span,
-                            ty::AdjustDerefRef(autoderefref));
-                    }
+                    assert!(!unsize);
+                    fcx.write_autoderef_adjustment(self_expr.id, autoderefs);
                 }
 
                 ty::ByReferenceExplicitSelfCategory(..) => {
@@ -260,14 +257,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     // autoref. Pull the region etc out of the type of first argument.
                     match transformed_self_ty.sty {
                         ty::ty_rptr(region, ty::mt { mutbl, ty: _ }) => {
-                            let ty::AutoDerefRef { autoderefs, autoref } = autoderefref;
-                            let autoref = autoref.map(|r| box r);
-                            fcx.write_adjustment(
-                                self_expr.id,
-                                span,
+                            fcx.write_adjustment(self_expr.id,
                                 ty::AdjustDerefRef(ty::AutoDerefRef {
                                     autoderefs: autoderefs,
-                                    autoref: Some(ty::AutoPtr(*region, mutbl, autoref))
+                                    autoref: Some(ty::AutoPtr(region, mutbl)),
+                                    unsize: if unsize {
+                                        Some(transformed_self_ty)
+                                    } else {
+                                        None
+                                    }
                                 }));
                         }
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 41eae881589..08e2f47c5a6 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -31,7 +31,6 @@ use std::rc::Rc;
 use util::ppaux::Repr;
 
 use self::CandidateKind::*;
-pub use self::PickAdjustment::*;
 pub use self::PickKind::*;
 
 struct ProbeContext<'a, 'tcx:'a> {
@@ -49,7 +48,8 @@ struct ProbeContext<'a, 'tcx:'a> {
 
 struct CandidateStep<'tcx> {
     self_ty: Ty<'tcx>,
-    adjustment: PickAdjustment,
+    autoderefs: usize,
+    unsize: bool
 }
 
 struct Candidate<'tcx> {
@@ -70,8 +70,24 @@ enum CandidateKind<'tcx> {
 
 pub struct Pick<'tcx> {
     pub method_ty: Rc<ty::Method<'tcx>>,
-    pub adjustment: PickAdjustment,
     pub kind: PickKind<'tcx>,
+
+    // Indicates that the source expression should be autoderef'd N times
+    //
+    // A = expr | *expr | **expr | ...
+    pub autoderefs: usize,
+
+    // Indicates that an autoref is applied after the optional autoderefs
+    //
+    // B = A | &A | &mut A
+    pub autoref: Option<ast::Mutability>,
+
+    // Indicates that the source expression should be "unsized" to a
+    // target type. This should probably eventually go away in favor
+    // of just coercing method receivers.
+    //
+    // C = B | unsize(B)
+    pub unsize: Option<Ty<'tcx>>,
 }
 
 #[derive(Clone,Debug)]
@@ -85,30 +101,6 @@ pub enum PickKind<'tcx> {
 
 pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
 
-// This is a kind of "abstracted" version of ty::AutoAdjustment.  The
-// difference is that it doesn't embed any regions or other
-// specifics. The "confirmation" step recreates those details as
-// needed.
-#[derive(Clone,Debug)]
-pub enum PickAdjustment {
-    // Indicates that the source expression should be autoderef'd N times
-    //
-    // A = expr | *expr | **expr
-    AutoDeref(usize),
-
-    // Indicates that the source expression should be autoderef'd N
-    // times and then "unsized". This should probably eventually go
-    // away in favor of just coercing method receivers.
-    //
-    // A = unsize(expr | *expr | **expr)
-    AutoUnsizeLength(/* number of autoderefs */ usize, /* length*/ usize),
-
-    // Indicates that an autoref is applied after some number of other adjustments
-    //
-    // A = &A | &mut A
-    AutoRef(ast::Mutability, Box<PickAdjustment>),
-}
-
 #[derive(PartialEq, Eq, Copy, Clone)]
 pub enum Mode {
     // An expression of the form `receiver.method_name(...)`.
@@ -149,7 +141,8 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     } else {
         vec![CandidateStep {
             self_ty: self_ty,
-            adjustment: AutoDeref(0)
+            autoderefs: 0,
+            unsize: false
         }]
     };
 
@@ -200,16 +193,21 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                                        UnresolvedTypeAction::Error,
                                                        NoPreference,
                                                        |t, d| {
-        let adjustment = AutoDeref(d);
-        steps.push(CandidateStep { self_ty: t, adjustment: adjustment });
+        steps.push(CandidateStep {
+            self_ty: t,
+            autoderefs: d,
+            unsize: false
+        });
         None::<()> // keep iterating until we can't anymore
     });
 
     match final_ty.sty {
-        ty::ty_vec(elem_ty, Some(len)) => {
+        ty::ty_vec(elem_ty, Some(_)) => {
+            let slice_ty = ty::mk_vec(fcx.tcx(), elem_ty, None);
             steps.push(CandidateStep {
-                self_ty: ty::mk_vec(fcx.tcx(), elem_ty, None),
-                adjustment: AutoUnsizeLength(dereferences, len),
+                self_ty: slice_ty,
+                autoderefs: dereferences,
+                unsize: true
             });
         }
         ty::ty_err => return None,
@@ -926,20 +924,21 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
          * consuming them for their entire lifetime.
          */
 
-        let adjustment = match step.adjustment {
-            AutoDeref(d) => consider_reborrow(step.self_ty, d),
-            AutoUnsizeLength(..) | AutoRef(..) => step.adjustment.clone(),
-        };
+        if step.unsize {
+            return None;
+        }
 
-        return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone()));
+        self.pick_method(step.self_ty).map(|r| r.map(|mut pick| {
+            pick.autoderefs = step.autoderefs;
 
-        fn consider_reborrow<'tcx>(ty: Ty<'tcx>, d: usize) -> PickAdjustment {
             // Insert a `&*` or `&mut *` if this is a reference type:
-            match ty.sty {
-                ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)),
-                _ => AutoDeref(d),
+            if let ty::ty_rptr(_, mt) = step.self_ty.sty {
+                pick.autoderefs += 1;
+                pick.autoref = Some(mt.mutbl);
             }
-        }
+
+            pick
+        }))
     }
 
     fn pick_autorefd_method(&mut self,
@@ -947,46 +946,28 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                             -> Option<PickResult<'tcx>>
     {
         let tcx = self.tcx();
-        self.search_mutabilities(
-            |m| AutoRef(m, box step.adjustment.clone()),
-            |m,r| ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty:step.self_ty, mutbl:m}))
-    }
 
-    fn search_mutabilities<F, G>(&mut self,
-                                 mut mk_adjustment: F,
-                                 mut mk_autoref_ty: G)
-                                 -> Option<PickResult<'tcx>> where
-        F: FnMut(ast::Mutability) -> PickAdjustment,
-        G: FnMut(ast::Mutability, ty::Region) -> Ty<'tcx>,
-    {
         // In general, during probing we erase regions. See
         // `impl_self_ty()` for an explanation.
-        let region = ty::ReStatic;
+        let region = tcx.mk_region(ty::ReStatic);
 
         // Search through mutabilities in order to find one where pick works:
-        [ast::MutImmutable, ast::MutMutable]
-            .iter()
-            .flat_map(|&m| {
-                let autoref_ty = mk_autoref_ty(m, region);
-                self.pick_method(autoref_ty)
-                    .map(|r| self.adjust(r, mk_adjustment(m)))
-                    .into_iter()
-            })
-            .nth(0)
-    }
-
-    fn adjust(&mut self,
-              result: PickResult<'tcx>,
-              adjustment: PickAdjustment)
-              -> PickResult<'tcx>
-    {
-        match result {
-            Err(e) => Err(e),
-            Ok(mut pick) => {
-                pick.adjustment = adjustment;
-                Ok(pick)
-            }
-        }
+        [ast::MutImmutable, ast::MutMutable].iter().filter_map(|&m| {
+            let autoref_ty = ty::mk_rptr(tcx, region, ty::mt {
+                ty: step.self_ty,
+                mutbl: m
+            });
+            self.pick_method(autoref_ty).map(|r| r.map(|mut pick| {
+                pick.autoderefs = step.autoderefs;
+                pick.autoref = Some(m);
+                pick.unsize = if step.unsize {
+                    Some(step.self_ty)
+                } else {
+                    None
+                };
+                pick
+            }))
+        }).nth(0)
     }
 
     fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
@@ -1122,8 +1103,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         let method_ty = probes[0].method_ty.clone();
         Some(Pick {
             method_ty: method_ty,
-            adjustment: AutoDeref(0),
-            kind: TraitPick(trait_def_id, method_num)
+            kind: TraitPick(trait_def_id, method_num),
+            autoderefs: 0,
+            autoref: None,
+            unsize: None
         })
     }
 
@@ -1296,7 +1279,6 @@ impl<'tcx> Candidate<'tcx> {
     fn to_unadjusted_pick(&self) -> Pick<'tcx> {
         Pick {
             method_ty: self.method_ty.clone(),
-            adjustment: AutoDeref(0),
             kind: match self.kind {
                 InherentImplCandidate(def_id, _) => {
                     InherentImplPick(def_id)
@@ -1323,7 +1305,10 @@ impl<'tcx> Candidate<'tcx> {
                 ProjectionCandidate(def_id, index) => {
                     TraitPick(def_id, index)
                 }
-            }
+            },
+            autoderefs: 0,
+            autoref: None,
+            unsize: None
         }
     }
 
@@ -1392,15 +1377,10 @@ impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> {
 
 impl<'tcx> Repr<'tcx> for CandidateStep<'tcx> {
     fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("CandidateStep({},{:?})",
+        format!("CandidateStep({}, autoderefs={}, unsize={})",
                 self.self_ty.repr(tcx),
-                self.adjustment)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for PickAdjustment {
-    fn repr(&self, _tcx: &ty::ctxt) -> String {
-        format!("{:?}", self)
+                self.autoderefs,
+                self.unsize)
     }
 }
 
@@ -1412,9 +1392,12 @@ impl<'tcx> Repr<'tcx> for PickKind<'tcx> {
 
 impl<'tcx> Repr<'tcx> for Pick<'tcx> {
     fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("Pick(method_ty={}, adjustment={:?}, kind={:?})",
+        format!("Pick(method_ty={}, autoderefs={},
+                 autoref={}, unsize={}, kind={:?})",
                 self.method_ty.repr(tcx),
-                self.adjustment,
+                self.autoderefs,
+                self.autoref.repr(tcx),
+                self.unsize.repr(tcx),
                 self.kind)
     }
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 862c454a388..a54adb3533a 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1292,21 +1292,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub fn write_autoderef_adjustment(&self,
                                       node_id: ast::NodeId,
-                                      span: Span,
                                       derefs: usize) {
-        if derefs == 0 { return; }
         self.write_adjustment(
             node_id,
-            span,
             ty::AdjustDerefRef(ty::AutoDerefRef {
                 autoderefs: derefs,
-                autoref: None })
+                autoref: None,
+                unsize: None
+            })
         );
     }
 
     pub fn write_adjustment(&self,
                             node_id: ast::NodeId,
-                            span: Span,
                             adj: ty::AutoAdjustment<'tcx>) {
         debug!("write_adjustment(node_id={}, adj={})", node_id, adj.repr(self.tcx()));
 
@@ -1314,13 +1312,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
-        // Careful: adjustments can imply trait obligations if we are
-        // casting from a concrete type to an object type. I think
-        // it'd probably be nicer to move the logic that creates the
-        // obligation into the code that creates the adjustment, but
-        // that's a bit awkward, so instead we go digging and pull the
-        // obligation out here.
-        self.register_adjustment_obligations(span, &adj);
         self.inh.adjustments.borrow_mut().insert(node_id, adj);
     }
 
@@ -1383,74 +1374,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                        cause)
     }
 
-    fn register_adjustment_obligations(&self,
-                                       span: Span,
-                                       adj: &ty::AutoAdjustment<'tcx>) {
-        match *adj {
-            ty::AdjustReifyFnPointer(..) => { }
-            ty::AdjustUnsafeFnPointer => { }
-            ty::AdjustDerefRef(ref d_r) => {
-                match d_r.autoref {
-                    Some(ref a_r) => {
-                        self.register_autoref_obligations(span, a_r);
-                    }
-                    None => {}
-                }
-            }
-        }
-    }
-
-    fn register_autoref_obligations(&self,
-                                    span: Span,
-                                    autoref: &ty::AutoRef<'tcx>) {
-        match *autoref {
-            ty::AutoUnsize(ref unsize) => {
-                self.register_unsize_obligations(span, unsize);
-            }
-            ty::AutoPtr(_, _, None) |
-            ty::AutoUnsafe(_, None) => {
-            }
-            ty::AutoPtr(_, _, Some(ref a_r)) |
-            ty::AutoUnsafe(_, Some(ref a_r)) => {
-                self.register_autoref_obligations(span, &**a_r)
-            }
-            ty::AutoUnsizeUniq(ref unsize) => {
-                self.register_unsize_obligations(span, unsize);
-            }
-        }
-    }
-
-    fn register_unsize_obligations(&self,
-                                   span: Span,
-                                   unsize: &ty::UnsizeKind<'tcx>) {
-        debug!("register_unsize_obligations: unsize={:?}", unsize);
-
-        match *unsize {
-            ty::UnsizeLength(..) => {}
-            ty::UnsizeStruct(ref u, _) => {
-                self.register_unsize_obligations(span, &**u)
-            }
-            ty::UnsizeVtable(ref ty_trait, self_ty) => {
-                vtable::check_object_safety(self.tcx(), ty_trait, span);
-
-                // If the type is `Foo+'a`, ensures that the type
-                // being cast to `Foo+'a` implements `Foo`:
-                vtable::register_object_cast_obligations(self,
-                                                         span,
-                                                         ty_trait,
-                                                         self_ty);
-
-                // If the type is `Foo+'a`, ensures that the type
-                // being cast to `Foo+'a` outlives `'a`:
-                let cause = traits::ObligationCause { span: span,
-                                                      body_id: self.body_id,
-                                                      code: traits::ObjectCastObligation(self_ty) };
-                self.register_region_obligation(self_ty, ty_trait.bounds.region_bound, cause);
-            }
-            ty::UnsizeUpcast(_) => { }
-        }
-    }
-
     /// Returns the type of `def_id` with all generics replaced by by fresh type/region variables.
     /// Also returns the substitution from the type parameters on `def_id` to the fresh variables.
     /// Registers any trait obligations specified on `def_id` at the same time.
@@ -1881,7 +1804,8 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
         let mt = match ty::deref(resolved_t, false) {
             Some(mt) => Some(mt),
             None => {
-                let method_call = opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs));
+                let method_call =
+                    opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs as u32));
 
                 // Super subtle: it might seem as though we should
                 // pass `opt_expr` to `try_overloaded_deref`, so that
@@ -1972,13 +1896,13 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 }
 
-fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
-                                       base_expr: &ast::Expr,
-                                       base_ty: Ty<'tcx>,
-                                       lvalue_pref: LvaluePreference,
-                                       mut step: F)
-                                       -> Option<T> where
-    F: FnMut(Ty<'tcx>, ty::AutoDerefRef<'tcx>) -> Option<T>,
+fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                             expr: &ast::Expr,
+                             base_expr: &'tcx ast::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
@@ -1991,9 +1915,9 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
                                                UnresolvedTypeAction::Error,
                                                lvalue_pref,
                                                |adj_ty, idx| {
-            let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
-            step(adj_ty, autoderefref)
-        });
+        try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr,
+                       adj_ty, idx, false, lvalue_pref, idx_ty)
+    });
 
     if final_mt.is_some() {
         return final_mt;
@@ -2001,41 +1925,38 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
 
     // After we have fully autoderef'd, if the resulting type is [T, ..n], then
     // do a final unsized coercion to yield [T].
-    match ty.sty {
-        ty::ty_vec(element_ty, Some(n)) => {
-            let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None);
-            let autoderefref = ty::AutoDerefRef {
-                autoderefs: autoderefs,
-                autoref: Some(ty::AutoUnsize(ty::UnsizeLength(n)))
-            };
-            step(adjusted_ty, autoderefref)
-        }
-        _ => {
-            None
-        }
+    if let ty::ty_vec(element_ty, Some(_)) = ty.sty {
+        let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None);
+        try_index_step(fcx, 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
-/// `autoderef_for_index`.
+/// `lookup_indexing`.
 fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                             method_call: MethodCall,
                             expr: &ast::Expr,
                             base_expr: &'tcx ast::Expr,
                             adjusted_ty: Ty<'tcx>,
-                            adjustment: ty::AutoDerefRef<'tcx>,
+                            autoderefs: usize,
+                            unsize: bool,
                             lvalue_pref: LvaluePreference,
                             index_ty: Ty<'tcx>)
                             -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
 {
     let tcx = fcx.tcx();
-    debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, adjustment={:?}, index_ty={})",
+    debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, \
+                           autoderefs={}, unsize={}, index_ty={})",
            expr.repr(tcx),
            base_expr.repr(tcx),
            adjusted_ty.repr(tcx),
-           adjustment,
+           autoderefs,
+           unsize,
            index_ty.repr(tcx));
 
     let input_ty = fcx.infcx().next_ty_var();
@@ -2044,7 +1965,9 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     match (ty::index(adjusted_ty), &index_ty.sty) {
         (Some(ty), &ty::ty_uint(ast::TyUs)) | (Some(ty), &ty::ty_infer(ty::IntVar(_))) => {
             debug!("try_index_step: success, using built-in indexing");
-            fcx.write_adjustment(base_expr.id, base_expr.span, ty::AdjustDerefRef(adjustment));
+            // If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
+            assert!(!unsize);
+            fcx.write_autoderef_adjustment(base_expr.id, autoderefs);
             return Some((tcx.types.usize, ty));
         }
         _ => {}
@@ -2058,7 +1981,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                              Some(&*base_expr),
                                              token::intern("index_mut"),
                                              trait_did,
-                                             adjustment.clone(),
+                                             autoderefs,
+                                             unsize,
                                              adjusted_ty,
                                              Some(vec![input_ty]))
         }
@@ -2073,7 +1997,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                              Some(&*base_expr),
                                              token::intern("index"),
                                              trait_did,
-                                             adjustment.clone(),
+                                             autoderefs,
+                                             unsize,
                                              adjusted_ty,
                                              Some(vec![input_ty]))
         }
@@ -2662,7 +2587,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
         match field_ty {
             Some(field_ty) => {
                 fcx.write_ty(expr.id, field_ty);
-                fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
+                fcx.write_autoderef_adjustment(base.id, autoderefs);
                 return;
             }
             None => {}
@@ -2773,7 +2698,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
         match field_ty {
             Some(field_ty) => {
                 fcx.write_ty(expr.id, field_ty);
-                fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
+                fcx.write_autoderef_adjustment(base.id, autoderefs);
                 return;
             }
             None => {}
@@ -3600,26 +3525,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                   fcx.write_ty(id, idx_t);
               } else {
                   let base_t = structurally_resolved_type(fcx, expr.span, base_t);
-
-                  let result =
-                      autoderef_for_index(fcx, &**base, base_t, lvalue_pref, |adj_ty, adj| {
-                          try_index_step(fcx,
-                                         MethodCall::expr(expr.id),
-                                         expr,
-                                         &**base,
-                                         adj_ty,
-                                         adj,
-                                         lvalue_pref,
-                                         idx_t)
-                      });
-
-                  match result {
+                  match lookup_indexing(fcx, expr, base, base_t, idx_t, lvalue_pref) {
                       Some((index_ty, element_ty)) => {
                           let idx_expr_ty = fcx.expr_ty(idx);
                           demand::eqtype(fcx, expr.span, index_ty, idx_expr_ty);
                           fcx.write_ty(id, element_ty);
                       }
-                      _ => {
+                      None => {
                           check_expr_has_type(fcx, &**idx, fcx.tcx().types.err);
                           fcx.type_error_message(
                               expr.span,
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 9554e6ad8aa..a7c2969fb7f 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -499,10 +499,10 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
     if let Some(adjustment) = rcx.fcx.inh.adjustments.borrow().get(&expr.id) {
         debug!("adjustment={:?}", adjustment);
         match *adjustment {
-            ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => {
+            ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => {
                 let expr_ty = rcx.resolve_node_type(expr.id);
                 constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
-                if let Some(ref autoref) = *opt_autoref {
+                if let Some(ref autoref) = *autoref {
                     link_autoref(rcx, expr, autoderefs, autoref);
 
                     // Require that the resulting region encompasses
@@ -872,7 +872,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
 
     let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id));
     for i in 0..derefs {
-        let method_call = MethodCall::autoderef(deref_expr.id, i);
+        let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
         debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
 
         derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) {
@@ -904,7 +904,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
                     let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
                     debug!("constrain_autoderefs: self_cmt={:?}",
                            self_cmt.repr(rcx.tcx()));
-                    link_region(rcx, deref_expr.span, *r,
+                    link_region(rcx, deref_expr.span, r,
                                 ty::BorrowKind::from_mutbl(m), self_cmt);
                 }
 
@@ -1102,7 +1102,7 @@ fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                 ast::PatVec(_, Some(ref slice_pat), _) => {
                     match mc.cat_slice_pattern(sub_cmt, &**slice_pat) {
                         Ok((slice_cmt, slice_mutbl, slice_r)) => {
-                            link_region(rcx, sub_pat.span, slice_r,
+                            link_region(rcx, sub_pat.span, &slice_r,
                                         ty::BorrowKind::from_mutbl(slice_mutbl),
                                         slice_cmt);
                         }
@@ -1127,16 +1127,15 @@ fn link_autoref(rcx: &Rcx,
     debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
 
     match *autoref {
-        ty::AutoPtr(r, m, _) => {
-            link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
+        ty::AutoPtr(r, m) => {
+            link_region(rcx, expr.span, r,
+                ty::BorrowKind::from_mutbl(m), expr_cmt);
         }
 
-        ty::AutoUnsafe(m, _) => {
+        ty::AutoUnsafe(m) => {
             let r = ty::ReScope(CodeExtent::from_node_id(expr.id));
             link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
         }
-
-        ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {}
     }
 }
 
@@ -1151,7 +1150,7 @@ fn link_by_ref(rcx: &Rcx,
     let mc = mc::MemCategorizationContext::new(rcx.fcx);
     let expr_cmt = ignore_err!(mc.cat_expr(expr));
     let borrow_region = ty::ReScope(callee_scope);
-    link_region(rcx, expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
+    link_region(rcx, 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
@@ -1169,7 +1168,7 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
         let tcx = rcx.fcx.ccx.tcx;
         debug!("rptr_ty={}", ty_to_string(tcx, rptr_ty));
         let r = ty::ty_region(tcx, span, rptr_ty);
-        link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl),
+        link_region(rcx, span, &r, ty::BorrowKind::from_mutbl(mutbl),
                     cmt_borrowed);
     }
 }
@@ -1179,7 +1178,7 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
 /// between regions, as explained in `link_reborrowed_region()`.
 fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                          span: Span,
-                         borrow_region: ty::Region,
+                         borrow_region: &ty::Region,
                          borrow_kind: ty::BorrowKind,
                          borrow_cmt: mc::cmt<'tcx>) {
     let mut borrow_cmt = borrow_cmt;
@@ -1273,7 +1272,7 @@ fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
 /// recurse and process `ref_cmt` (see case 2 above).
 fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                                     span: Span,
-                                    borrow_region: ty::Region,
+                                    borrow_region: &ty::Region,
                                     borrow_kind: ty::BorrowKind,
                                     ref_cmt: mc::cmt<'tcx>,
                                     ref_region: ty::Region,
@@ -1318,7 +1317,7 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
     debug!("link_reborrowed_region: {} <= {}",
            borrow_region.repr(rcx.tcx()),
            ref_region.repr(rcx.tcx()));
-    rcx.fcx.mk_subr(cause, borrow_region, ref_region);
+    rcx.fcx.mk_subr(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
diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs
index 63c34b65d77..f301c89333e 100644
--- a/src/librustc_typeck/check/vtable.rs
+++ b/src/librustc_typeck/check/vtable.rs
@@ -15,7 +15,6 @@ use middle::traits::report_fulfillment_errors;
 use middle::ty::{self, Ty, AsPredicate};
 use syntax::ast;
 use syntax::codemap::Span;
-use util::nodemap::FnvHashSet;
 use util::ppaux::{Repr, UserString};
 
 
@@ -133,46 +132,9 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         fcx.register_predicate(projection_obligation);
     }
 
-    // Finally, check that there IS a projection predicate for every associated type.
-    check_object_type_binds_all_associated_types(fcx.tcx(),
-                                                 span,
-                                                 object_trait);
-
     object_trait_ref
 }
 
-fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                                      span: Span,
-                                                      object_trait: &ty::TyTrait<'tcx>)
-{
-    let object_trait_ref =
-        object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
-
-    let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
-        traits::supertraits(tcx, object_trait_ref.clone())
-        .flat_map(|tr| {
-            let trait_def = ty::lookup_trait_def(tcx, 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_trait.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.user_string(tcx),
-                    ty::item_path_str(tcx, trait_def_id));
-    }
-}
-
 pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) {
     debug!("select_all_fcx_obligations_and_apply_defaults");
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 37f43252483..f778a64f949 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -285,11 +285,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             }
 
             Some(adjustment) => {
-                let adj_object = ty::adjust_is_object(&adjustment);
                 let resolved_adjustment = match adjustment {
-                    ty::AdjustReifyFnPointer(def_id) => {
-                        ty::AdjustReifyFnPointer(def_id)
-                    }
+                    ty::AdjustReifyFnPointer => ty::AdjustReifyFnPointer,
 
                     ty::AdjustUnsafeFnPointer => {
                         ty::AdjustUnsafeFnPointer
@@ -297,18 +294,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 
                     ty::AdjustDerefRef(adj) => {
                         for autoderef in 0..adj.autoderefs {
-                            let method_call = MethodCall::autoderef(id, autoderef);
-                            self.visit_method_map_entry(reason, method_call);
-                        }
-
-                        if adj_object {
-                            let method_call = MethodCall::autoobject(id);
+                            let method_call = MethodCall::autoderef(id, autoderef as u32);
                             self.visit_method_map_entry(reason, method_call);
                         }
 
                         ty::AdjustDerefRef(ty::AutoDerefRef {
                             autoderefs: adj.autoderefs,
                             autoref: self.resolve(&adj.autoref, reason),
+                            unsize: self.resolve(&adj.unsize, reason),
                         })
                     }
                 };
diff --git a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs
index c55e24e81ad..c18d72c445b 100644
--- a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs
+++ b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs
@@ -34,6 +34,8 @@ fn dent<C:BoxCar>(c: C, color: C::Color) {
 
 fn dent_object<COLOR>(c: BoxCar<Color=COLOR>) {
     //~^ ERROR ambiguous associated type
+    //~| ERROR the associated type `Color` (from the trait `Box`) must be specified
+    //~| ERROR the associated type `Color` (from the trait `Vehicle`) must be specified
 }
 
 fn paint<C:BoxCar>(c: C, d: C::Color) {
diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs
index 951d78410b8..01fc4fef03b 100644
--- a/src/test/compile-fail/issue-18819.rs
+++ b/src/test/compile-fail/issue-18819.rs
@@ -20,7 +20,7 @@ impl Foo for X {
     type Item = bool;
 }
 
-fn print_x(_: &Foo, extra: &str) {
+fn print_x(_: &Foo<Item=bool>, extra: &str) {
     println!("{}", extra);
 }
 
diff --git a/src/test/run-pass/issue-19121.rs b/src/test/compile-fail/issue-19482.rs
index e02d001ee98..21a50f24d5e 100644
--- a/src/test/run-pass/issue-19121.rs
+++ b/src/test/compile-fail/issue-19482.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // Test that a partially specified trait object with unspecified associated
-// type does not ICE.
+// type does not type-check.
 
 // pretty-expanded FIXME #23616
 
@@ -20,7 +20,6 @@ trait Foo {
 }
 
 fn bar(x: &Foo) {}
-// FIXME(#19482) -- `Foo` should specify `A`, but this is not
-// currently enforced except at object creation
+//~^ ERROR the associated type `A` (from the trait `Foo`) must be specified
 
 pub fn main() {}
diff --git a/src/test/compile-fail/retslot-cast.rs b/src/test/compile-fail/retslot-cast.rs
index 4ef07ecb438..c5e26a26744 100644
--- a/src/test/compile-fail/retslot-cast.rs
+++ b/src/test/compile-fail/retslot-cast.rs
@@ -11,7 +11,8 @@
 #![feature(rustc_attrs)]
 #![allow(warnings)]
 
-pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> {
+pub fn fail(x: Option<&(Iterator<Item=()>+Send)>)
+            -> Option<&Iterator<Item=()>> {
     // This call used to trigger an LLVM assertion because the return
     // slot had type "Option<&Iterator>"* instead of
     // "Option<&(Iterator+Send)>"* -- but this now yields a
@@ -23,7 +24,8 @@ pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> {
     inner(x) //~ ERROR mismatched types
 }
 
-pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> {
+pub fn inner(x: Option<&(Iterator<Item=()>+Send)>)
+             -> Option<&(Iterator<Item=()>+Send)> {
     x
 }
 
diff --git a/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs b/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs
index 55156e28cd7..5a821ef1231 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs
@@ -11,7 +11,7 @@
 
 // Test that the `Fn` traits require `()` form without a feature gate.
 
-fn bar1(x: &Fn<()>) {
+fn bar1(x: &Fn<(), Output=()>) {
     //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family
 }