about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2016-12-20 22:46:11 +0200
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2016-12-28 11:29:19 +0200
commitf89856be6ccd1f63ef72d343587cd5d7932cfe8b (patch)
tree9b4f669599c395c6b0e5891f155ae898f113d636 /src
parente64f64a2fc1deb955b42542fa399f2fa2b609866 (diff)
downloadrust-f89856be6ccd1f63ef72d343587cd5d7932cfe8b.tar.gz
rust-f89856be6ccd1f63ef72d343587cd5d7932cfe8b.zip
rustc: move function arguments into hir::Body.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/dep_graph/graph.rs6
-rw-r--r--src/librustc/hir/intravisit.rs45
-rw-r--r--src/librustc/hir/lowering.rs71
-rw-r--r--src/librustc/hir/map/blocks.rs7
-rw-r--r--src/librustc/hir/map/mod.rs4
-rw-r--r--src/librustc/hir/mod.rs18
-rw-r--r--src/librustc/hir/print.rs194
-rw-r--r--src/librustc/infer/error_reporting.rs51
-rw-r--r--src/librustc/middle/cstore.rs32
-rw-r--r--src/librustc/middle/dataflow.rs26
-rw-r--r--src/librustc/middle/dead.rs6
-rw-r--r--src/librustc/middle/expr_use_visitor.rs17
-rw-r--r--src/librustc/middle/liveness.rs12
-rw-r--r--src/librustc/middle/reachable.rs7
-rw-r--r--src/librustc/middle/resolve_lifetime.rs9
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs3
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs3
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs37
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs5
-rw-r--r--src/librustc_const_eval/check_match.rs41
-rw-r--r--src/librustc_const_eval/eval.rs20
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs6
-rw-r--r--src/librustc_lint/bad_style.rs19
-rw-r--r--src/librustc_lint/builtin.rs6
-rw-r--r--src/librustc_lint/types.rs4
-rw-r--r--src/librustc_lint/unused.rs6
-rw-r--r--src/librustc_metadata/cstore_impl.rs6
-rw-r--r--src/librustc_metadata/encoder.rs44
-rw-r--r--src/librustc_mir/build/matches/mod.rs2
-rw-r--r--src/librustc_mir/build/mod.rs9
-rw-r--r--src/librustc_mir/build/scope.rs6
-rw-r--r--src/librustc_mir/mir_map.rs5
-rw-r--r--src/librustc_passes/consts.rs2
-rw-r--r--src/librustc_passes/rvalues.rs2
-rw-r--r--src/librustc_typeck/astconv.rs56
-rw-r--r--src/librustc_typeck/check/compare_method.rs10
-rw-r--r--src/librustc_typeck/check/intrinsic.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs58
-rw-r--r--src/librustc_typeck/check/regionck.rs13
-rw-r--r--src/librustc_typeck/check/upvar.rs5
-rw-r--r--src/librustc_typeck/check/wfcheck.rs2
-rw-r--r--src/librustc_typeck/check/writeback.rs51
-rw-r--r--src/librustc_typeck/collect.rs29
-rw-r--r--src/librustc_typeck/rscope.rs6
-rw-r--r--src/librustdoc/clean/mod.rs121
-rw-r--r--src/librustdoc/doctree.rs1
-rw-r--r--src/librustdoc/visit_ast.rs8
-rw-r--r--src/test/compile-fail/explicit-self-lifetime-mismatch.rs6
-rw-r--r--src/test/incremental/hashes/trait_defs.rs12
50 files changed, 545 insertions, 568 deletions
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 2637d34c5c5..26e1dc7e049 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -51,6 +51,12 @@ impl DepGraph {
         }
     }
 
+    /// True if we are actually building the full dep-graph.
+    #[inline]
+    pub fn is_fully_enabled(&self) -> bool {
+        self.data.thread.is_fully_enabled()
+    }
+
     pub fn query(&self) -> DepGraphQuery<DefId> {
         self.data.thread.query()
     }
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 845b6473259..4b171193b4a 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -395,6 +395,10 @@ pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_node_i
 }
 
 pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
+    for argument in &body.arguments {
+        visitor.visit_id(argument.id);
+        visitor.visit_pat(&argument.pat);
+    }
     visitor.visit_expr(&body.value);
 }
 
@@ -680,9 +684,12 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v
     visitor.visit_name(foreign_item.span, foreign_item.name);
 
     match foreign_item.node {
-        ForeignItemFn(ref function_declaration, ref generics) => {
+        ForeignItemFn(ref function_declaration, ref names, ref generics) => {
+            visitor.visit_generics(generics);
             visitor.visit_fn_decl(function_declaration);
-            visitor.visit_generics(generics)
+            for name in names {
+                visitor.visit_name(name.span, name.node);
+            }
         }
         ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ),
     }
@@ -750,18 +757,8 @@ pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionR
 }
 
 pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
-    for argument in &function_declaration.inputs {
-        visitor.visit_id(argument.id);
-        visitor.visit_pat(&argument.pat);
-        visitor.visit_ty(&argument.ty)
-    }
-    walk_fn_ret_ty(visitor, &function_declaration.output)
-}
-
-pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
-    for argument in &function_declaration.inputs {
-        visitor.visit_id(argument.id);
-        visitor.visit_ty(&argument.ty)
+    for ty in &function_declaration.inputs {
+        visitor.visit_ty(ty)
     }
     walk_fn_ret_ty(visitor, &function_declaration.output)
 }
@@ -799,12 +796,15 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_nested_body, default);
         }
-        TraitItemKind::Method(ref sig, None) => {
+        TraitItemKind::Method(ref sig, TraitMethod::Required(ref names)) => {
             visitor.visit_id(trait_item.id);
             visitor.visit_generics(&sig.generics);
             visitor.visit_fn_decl(&sig.decl);
+            for name in names {
+                visitor.visit_name(name.span, name.node);
+            }
         }
-        TraitItemKind::Method(ref sig, Some(body_id)) => {
+        TraitItemKind::Method(ref sig, TraitMethod::Provided(body_id)) => {
             visitor.visit_fn(FnKind::Method(trait_item.name,
                                             sig,
                                             None,
@@ -1113,16 +1113,3 @@ impl<'a, 'ast> Visitor<'ast> for IdRangeComputingVisitor<'a, 'ast> {
         self.result.add(id);
     }
 }
-
-/// Computes the id range for a single fn body, ignoring nested items.
-pub fn compute_id_range_for_fn_body<'v>(fk: FnKind<'v>,
-                                        decl: &'v FnDecl,
-                                        body: BodyId,
-                                        sp: Span,
-                                        id: NodeId,
-                                        map: &map::Map<'v>)
-                                        -> IdRange {
-    let mut visitor = IdRangeComputingVisitor::new(map);
-    visitor.visit_fn(fk, decl, body, sp, id);
-    visitor.result()
-}
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index c858436e7fc..9a2658f48f3 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -170,8 +170,12 @@ impl<'a> LoweringContext<'a> {
         visit::walk_crate(&mut item_lowerer, c);
     }
 
-    fn record_body(&mut self, value: hir::Expr) -> hir::BodyId {
+    fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>)
+                   -> hir::BodyId {
         let body = hir::Body {
+            arguments: decl.map_or(hir_vec![], |decl| {
+                decl.inputs.iter().map(|x| self.lower_arg(x)).collect()
+            }),
             value: value
         };
         let id = body.id();
@@ -310,11 +314,11 @@ impl<'a> LoweringContext<'a> {
                 TyKind::Array(ref ty, ref length) => {
                     let length = self.lower_expr(length);
                     hir::TyArray(self.lower_ty(ty),
-                                 self.record_body(length))
+                                 self.record_body(length, None))
                 }
                 TyKind::Typeof(ref expr) => {
                     let expr = self.lower_expr(expr);
-                    hir::TyTypeof(self.record_body(expr))
+                    hir::TyTypeof(self.record_body(expr, None))
                 }
                 TyKind::PolyTraitRef(ref bounds) => {
                     hir::TyPolyTraitRef(self.lower_bounds(bounds))
@@ -343,7 +347,7 @@ impl<'a> LoweringContext<'a> {
                 data: self.lower_variant_data(&v.node.data),
                 disr_expr: v.node.disr_expr.as_ref().map(|e| {
                     let e = self.lower_expr(e);
-                    self.record_body(e)
+                    self.record_body(e, None)
                 }),
             },
             span: v.span,
@@ -532,13 +536,24 @@ impl<'a> LoweringContext<'a> {
         hir::Arg {
             id: arg.id,
             pat: self.lower_pat(&arg.pat),
-            ty: self.lower_ty(&arg.ty),
         }
     }
 
+    fn lower_fn_args_to_names(&mut self, decl: &FnDecl)
+                              -> hir::HirVec<Spanned<Name>> {
+        decl.inputs.iter().map(|arg| {
+            match arg.pat.node {
+                PatKind::Ident(_, ident, None) => {
+                    respan(ident.span, ident.node.name)
+                }
+                _ => respan(arg.pat.span, keywords::Invalid.name()),
+            }
+        }).collect()
+    }
+
     fn lower_fn_decl(&mut self, decl: &FnDecl) -> P<hir::FnDecl> {
         P(hir::FnDecl {
-            inputs: decl.inputs.iter().map(|x| self.lower_arg(x)).collect(),
+            inputs: decl.inputs.iter().map(|arg| self.lower_ty(&arg.ty)).collect(),
             output: match decl.output {
                 FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)),
                 FunctionRetTy::Default(span) => hir::DefaultReturn(span),
@@ -869,17 +884,17 @@ impl<'a> LoweringContext<'a> {
                 let value = self.lower_expr(e);
                 hir::ItemStatic(self.lower_ty(t),
                                 self.lower_mutability(m),
-                                self.record_body(value))
+                                self.record_body(value, None))
             }
             ItemKind::Const(ref t, ref e) => {
                 let value = self.lower_expr(e);
                 hir::ItemConst(self.lower_ty(t),
-                               self.record_body(value))
+                               self.record_body(value, None))
             }
             ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
                 let body = self.lower_block(body);
                 let body = self.expr_block(body, ThinVec::new());
-                let body_id = self.record_body(body);
+                let body_id = self.record_body(body, Some(decl));
                 hir::ItemFn(self.lower_fn_decl(decl),
                             self.lower_unsafety(unsafety),
                             self.lower_constness(constness),
@@ -948,16 +963,20 @@ impl<'a> LoweringContext<'a> {
                         hir::TraitItemKind::Const(this.lower_ty(ty),
                                                   default.as_ref().map(|x| {
                             let value = this.lower_expr(x);
-                            this.record_body(value)
+                            this.record_body(value, None)
                         }))
                     }
-                    TraitItemKind::Method(ref sig, ref body) => {
+                    TraitItemKind::Method(ref sig, None) => {
+                        let names = this.lower_fn_args_to_names(&sig.decl);
                         hir::TraitItemKind::Method(this.lower_method_sig(sig),
-                                                   body.as_ref().map(|x| {
-                            let body = this.lower_block(x);
-                            let expr = this.expr_block(body, ThinVec::new());
-                            this.record_body(expr)
-                        }))
+                                                   hir::TraitMethod::Required(names))
+                    }
+                    TraitItemKind::Method(ref sig, Some(ref body)) => {
+                        let body = this.lower_block(body);
+                        let expr = this.expr_block(body, ThinVec::new());
+                        let body_id = this.record_body(expr, Some(&sig.decl));
+                        hir::TraitItemKind::Method(this.lower_method_sig(sig),
+                                                   hir::TraitMethod::Provided(body_id))
                     }
                     TraitItemKind::Type(ref bounds, ref default) => {
                         hir::TraitItemKind::Type(this.lower_bounds(bounds),
@@ -1005,13 +1024,13 @@ impl<'a> LoweringContext<'a> {
                 node: match i.node {
                     ImplItemKind::Const(ref ty, ref expr) => {
                         let value = this.lower_expr(expr);
-                        let body_id = this.record_body(value);
+                        let body_id = this.record_body(value, None);
                         hir::ImplItemKind::Const(this.lower_ty(ty), body_id)
                     }
                     ImplItemKind::Method(ref sig, ref body) => {
                         let body = this.lower_block(body);
                         let expr = this.expr_block(body, ThinVec::new());
-                        let body_id = this.record_body(expr);
+                        let body_id = this.record_body(expr, Some(&sig.decl));
                         hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id)
                     }
                     ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
@@ -1097,7 +1116,9 @@ impl<'a> LoweringContext<'a> {
                 attrs: this.lower_attrs(&i.attrs),
                 node: match i.node {
                     ForeignItemKind::Fn(ref fdec, ref generics) => {
-                        hir::ForeignItemFn(this.lower_fn_decl(fdec), this.lower_generics(generics))
+                        hir::ForeignItemFn(this.lower_fn_decl(fdec),
+                                           this.lower_fn_args_to_names(fdec),
+                                           this.lower_generics(generics))
                     }
                     ForeignItemKind::Static(ref t, m) => {
                         hir::ForeignItemStatic(this.lower_ty(t), m)
@@ -1367,7 +1388,7 @@ impl<'a> LoweringContext<'a> {
                 ExprKind::Repeat(ref expr, ref count) => {
                     let expr = P(self.lower_expr(expr));
                     let count = self.lower_expr(count);
-                    hir::ExprRepeat(expr, self.record_body(count))
+                    hir::ExprRepeat(expr, self.record_body(count, None))
                 }
                 ExprKind::Tup(ref elts) => {
                     hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect())
@@ -1450,7 +1471,7 @@ impl<'a> LoweringContext<'a> {
                         let expr = this.lower_expr(body);
                         hir::ExprClosure(this.lower_capture_clause(capture_clause),
                                          this.lower_fn_decl(decl),
-                                         this.record_body(expr),
+                                         this.record_body(expr, Some(decl)),
                                          fn_decl_span)
                     })
                 }
@@ -1734,13 +1755,7 @@ impl<'a> LoweringContext<'a> {
                     // `::std::option::Option::Some(<pat>) => <body>`
                     let pat_arm = {
                         let body_block = self.lower_block(body);
-                        let body_span = body_block.span;
-                        let body_expr = P(hir::Expr {
-                            id: self.next_id(),
-                            node: hir::ExprBlock(body_block),
-                            span: body_span,
-                            attrs: ThinVec::new(),
-                        });
+                        let body_expr = P(self.expr_block(body_block, ThinVec::new()));
                         let pat = self.lower_pat(pat);
                         let some_pat = self.pat_some(e.span, pat);
 
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 001a4d1526d..6e08b52f9a2 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -62,7 +62,10 @@ impl MaybeFnLike for ast::Item {
 
 impl MaybeFnLike for ast::TraitItem {
     fn is_fn_like(&self) -> bool {
-        match self.node { ast::TraitItemKind::Method(_, Some(_)) => true, _ => false, }
+        match self.node {
+            ast::TraitItemKind::Method(_, ast::TraitMethod::Provided(_)) => true,
+            _ => false,
+        }
     }
 }
 
@@ -252,7 +255,7 @@ impl<'a> FnLikeNode<'a> {
                 _ => bug!("item FnLikeNode that is not fn-like"),
             },
             map::NodeTraitItem(ti) => match ti.node {
-                ast::TraitItemKind::Method(ref sig, Some(body)) => {
+                ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
                     method(ti.id, ti.name, sig, None, body, ti.span, &ti.attrs)
                 }
                 _ => bug!("trait method FnLikeNode that is not fn-like"),
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index ff9d12bb4f1..330583c0d88 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -389,7 +389,9 @@ impl<'ast> Map<'ast> {
     fn is_trait_item_body(&self, node_id: NodeId, item: &TraitItem) -> bool {
         match item.node {
             TraitItemKind::Const(_, Some(body)) |
-            TraitItemKind::Method(_, Some(body)) => body.node_id == node_id,
+            TraitItemKind::Method(_, TraitMethod::Provided(body)) => {
+                body.node_id == node_id
+            }
             _ => false
         }
     }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index b4a42711e4d..73097389c18 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -868,6 +868,7 @@ pub struct BodyId {
 /// The body of a function or constant value.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct Body {
+    pub arguments: HirVec<Arg>,
     pub value: Expr
 }
 
@@ -1102,6 +1103,16 @@ pub struct TraitItem {
     pub span: Span,
 }
 
+/// A trait method's body (or just argument names).
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitMethod {
+    /// No default body in the trait, just a signature.
+    Required(HirVec<Spanned<Name>>),
+
+    /// Both signature and body are provided in the trait.
+    Provided(BodyId),
+}
+
 /// Represents a trait method or associated constant or type
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum TraitItemKind {
@@ -1109,7 +1120,7 @@ pub enum TraitItemKind {
     /// must contain a value)
     Const(P<Ty>, Option<BodyId>),
     /// A method with an optional body
-    Method(MethodSig, Option<BodyId>),
+    Method(MethodSig, TraitMethod),
     /// An associated type with (possibly empty) bounds and optional concrete
     /// type
     Type(TyParamBounds, Option<P<Ty>>),
@@ -1248,7 +1259,6 @@ pub struct InlineAsm {
 /// represents an argument in a function header
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct Arg {
-    pub ty: P<Ty>,
     pub pat: P<Pat>,
     pub id: NodeId,
 }
@@ -1256,7 +1266,7 @@ pub struct Arg {
 /// Represents the header (not the body) of a function declaration
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct FnDecl {
-    pub inputs: HirVec<Arg>,
+    pub inputs: HirVec<P<Ty>>,
     pub output: FunctionRetTy,
     pub variadic: bool,
 }
@@ -1639,7 +1649,7 @@ pub struct ForeignItem {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum ForeignItem_ {
     /// A foreign function
-    ForeignItemFn(P<FnDecl>, Generics),
+    ForeignItemFn(P<FnDecl>, HirVec<Spanned<Name>>, Generics),
     /// A foreign static item (`static ext: u8`), with optional mutability
     /// (the boolean is true when mutable)
     ForeignItemStatic(P<Ty>, bool),
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 9518113b5a0..a7ffce37ee4 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -20,7 +20,6 @@ use syntax::print::pp::{Breaks, eof};
 use syntax::print::pp::Breaks::{Consistent, Inconsistent};
 use syntax::print::pprust::{self as ast_pp, PrintState};
 use syntax::ptr::P;
-use syntax::symbol::keywords;
 use syntax_pos::{self, BytePos};
 use errors;
 
@@ -267,10 +266,6 @@ pub fn where_clause_to_string(i: &hir::WhereClause) -> String {
     to_string(|s| s.print_where_clause(i))
 }
 
-pub fn fn_block_to_string(p: &hir::FnDecl) -> String {
-    to_string(|s| s.print_fn_block_args(p))
-}
-
 pub fn path_to_string(p: &hir::Path) -> String {
     to_string(|s| s.print_path(p, false))
 }
@@ -283,24 +278,35 @@ pub fn name_to_string(name: ast::Name) -> String {
     to_string(|s| s.print_name(name))
 }
 
-pub fn fun_to_string(decl: &hir::FnDecl,
-                     unsafety: hir::Unsafety,
-                     constness: hir::Constness,
-                     name: ast::Name,
-                     generics: &hir::Generics)
-                     -> String {
-    to_string(|s| {
-        s.head("")?;
-        s.print_fn(decl,
-                   unsafety,
-                   constness,
-                   Abi::Rust,
-                   Some(name),
-                   generics,
-                   &hir::Inherited)?;
-        s.end()?; // Close the head box
-        s.end() // Close the outer box
-    })
+pub fn fn_decl_in_crate_to_string(krate: &hir::Crate,
+                                  decl: &hir::FnDecl,
+                                  unsafety: hir::Unsafety,
+                                  constness: hir::Constness,
+                                  name: ast::Name,
+                                  generics: &hir::Generics,
+                                  body_id: hir::BodyId)
+                                  -> String {
+
+    let mut wr = Vec::new();
+    {
+        let mut s = rust_printer(Box::new(&mut wr), Some(krate));
+        (|s: &mut State| {
+            s.head("")?;
+            s.print_fn(decl,
+                       unsafety,
+                       constness,
+                       Abi::Rust,
+                       Some(name),
+                       generics,
+                       &hir::Inherited,
+                       &[],
+                       Some(body_id))?;
+            s.end()?; // Close the head box
+            s.end()?; // Close the outer box
+            eof(&mut s.s)
+        })(&mut s).unwrap();
+    }
+    String::from_utf8(wr).unwrap()
 }
 
 pub fn block_to_string(blk: &hir::Block) -> String {
@@ -317,10 +323,6 @@ pub fn variant_to_string(var: &hir::Variant) -> String {
     to_string(|s| s.print_variant(var))
 }
 
-pub fn arg_to_string(arg: &hir::Arg) -> String {
-    to_string(|s| s.print_arg(arg, false))
-}
-
 pub fn visibility_qualified(vis: &hir::Visibility, s: &str) -> String {
     match *vis {
         hir::Public => format!("pub {}", s),
@@ -569,7 +571,7 @@ impl<'a> State<'a> {
         self.maybe_print_comment(item.span.lo)?;
         self.print_outer_attributes(&item.attrs)?;
         match item.node {
-            hir::ForeignItemFn(ref decl, ref generics) => {
+            hir::ForeignItemFn(ref decl, ref arg_names, ref generics) => {
                 self.head("")?;
                 self.print_fn(decl,
                               hir::Unsafety::Normal,
@@ -577,7 +579,9 @@ impl<'a> State<'a> {
                               Abi::Rust,
                               Some(item.name),
                               generics,
-                              &item.vis)?;
+                              &item.vis,
+                              arg_names,
+                              None)?;
                 self.end()?; // end head-ibox
                 word(&mut self.s, ";")?;
                 self.end() // end the outer fn box
@@ -644,13 +648,14 @@ impl<'a> State<'a> {
         }
     }
 
+    fn maybe_body(&mut self, body_id: hir::BodyId) -> Option<&'a hir::Body> {
+        self.krate.map(|krate| krate.body(body_id))
+    }
+
     fn print_body_id(&mut self, body_id: hir::BodyId) -> io::Result<()> {
-        if let Some(krate) = self.krate {
-            let expr = &krate.body(body_id).value;
-            self.print_expr(expr)
-        } else {
-            Ok(())
-        }
+        self.maybe_body(body_id).map_or(Ok(()), |body| {
+            self.print_expr(&body.value)
+        })
     }
 
     /// Pretty-print an item
@@ -734,7 +739,9 @@ impl<'a> State<'a> {
                               abi,
                               Some(item.name),
                               typarams,
-                              &item.vis)?;
+                              &item.vis,
+                              &[],
+                              Some(body))?;
                 word(&mut self.s, " ")?;
                 self.end()?; // need to close a box
                 self.end()?; // need to close a box
@@ -995,7 +1002,9 @@ impl<'a> State<'a> {
     pub fn print_method_sig(&mut self,
                             name: ast::Name,
                             m: &hir::MethodSig,
-                            vis: &hir::Visibility)
+                            vis: &hir::Visibility,
+                            arg_names: &[Spanned<ast::Name>],
+                            body_id: Option<hir::BodyId>)
                             -> io::Result<()> {
         self.print_fn(&m.decl,
                       m.unsafety,
@@ -1003,7 +1012,9 @@ impl<'a> State<'a> {
                       m.abi,
                       Some(name),
                       &m.generics,
-                      vis)
+                      vis,
+                      arg_names,
+                      body_id)
     }
 
     pub fn print_trait_item_ref(&mut self, item_ref: &hir::TraitItemRef) -> io::Result<()> {
@@ -1025,19 +1036,17 @@ impl<'a> State<'a> {
             hir::TraitItemKind::Const(ref ty, default) => {
                 self.print_associated_const(ti.name, &ty, default, &hir::Inherited)?;
             }
-            hir::TraitItemKind::Method(ref sig, body) => {
-                if body.is_some() {
-                    self.head("")?;
-                }
-                self.print_method_sig(ti.name, sig, &hir::Inherited)?;
-                if let Some(body) = body {
-                    self.nbsp()?;
-                    self.end()?; // need to close a box
-                    self.end()?; // need to close a box
-                    self.print_body_id(body)?;
-                } else {
-                    word(&mut self.s, ";")?;
-                }
+            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref arg_names)) => {
+                self.print_method_sig(ti.name, sig, &hir::Inherited, arg_names, None)?;
+                word(&mut self.s, ";")?;
+            }
+            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
+                self.head("")?;
+                self.print_method_sig(ti.name, sig, &hir::Inherited, &[], Some(body))?;
+                self.nbsp()?;
+                self.end()?; // need to close a box
+                self.end()?; // need to close a box
+                self.print_body_id(body)?;
             }
             hir::TraitItemKind::Type(ref bounds, ref default) => {
                 self.print_associated_type(ti.name,
@@ -1075,7 +1084,7 @@ impl<'a> State<'a> {
             }
             hir::ImplItemKind::Method(ref sig, body) => {
                 self.head("")?;
-                self.print_method_sig(ii.name, sig, &ii.vis)?;
+                self.print_method_sig(ii.name, sig, &ii.vis, &[], Some(body))?;
                 self.nbsp()?;
                 self.end()?; // need to close a box
                 self.end()?; // need to close a box
@@ -1442,7 +1451,7 @@ impl<'a> State<'a> {
             hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span) => {
                 self.print_capture_clause(capture_clause)?;
 
-                self.print_fn_block_args(&decl)?;
+                self.print_closure_args(&decl, body)?;
                 space(&mut self.s)?;
 
                 // this is a bare expression
@@ -1966,7 +1975,9 @@ impl<'a> State<'a> {
                     abi: Abi,
                     name: Option<ast::Name>,
                     generics: &hir::Generics,
-                    vis: &hir::Visibility)
+                    vis: &hir::Visibility,
+                    arg_names: &[Spanned<ast::Name>],
+                    body_id: Option<hir::BodyId>)
                     -> io::Result<()> {
         self.print_fn_header_info(unsafety, constness, abi, vis)?;
 
@@ -1975,24 +1986,58 @@ impl<'a> State<'a> {
             self.print_name(name)?;
         }
         self.print_generics(generics)?;
-        self.print_fn_args_and_ret(decl)?;
-        self.print_where_clause(&generics.where_clause)
-    }
 
-    pub fn print_fn_args_and_ret(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
         self.popen()?;
-        self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?;
+        let mut i = 0;
+        // Make sure we aren't supplied *both* `arg_names` and `body_id`.
+        assert!(arg_names.is_empty() || body_id.is_none());
+        let args = body_id.and_then(|body_id| self.maybe_body(body_id))
+                          .map_or(&[][..], |body| &body.arguments[..]);
+        self.commasep(Inconsistent, &decl.inputs, |s, ty| {
+            s.ibox(indent_unit)?;
+            if let Some(name) = arg_names.get(i) {
+                word(&mut s.s, &name.node.as_str())?;
+                word(&mut s.s, ":")?;
+                space(&mut s.s)?;
+            } else if let Some(arg) = args.get(i) {
+                s.print_pat(&arg.pat)?;
+                word(&mut s.s, ":")?;
+                space(&mut s.s)?;
+            }
+            i += 1;
+            s.print_type(ty)?;
+            s.end()
+        })?;
         if decl.variadic {
             word(&mut self.s, ", ...")?;
         }
         self.pclose()?;
 
-        self.print_fn_output(decl)
+        self.print_fn_output(decl)?;
+        self.print_where_clause(&generics.where_clause)
     }
 
-    pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
+    fn print_closure_args(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) -> io::Result<()> {
         word(&mut self.s, "|")?;
-        self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true))?;
+        let mut i = 0;
+        let args = self.maybe_body(body_id).map_or(&[][..], |body| &body.arguments[..]);
+        self.commasep(Inconsistent, &decl.inputs, |s, ty| {
+            s.ibox(indent_unit)?;
+
+            if let Some(arg) = args.get(i) {
+                s.print_pat(&arg.pat)?;
+            } else {
+                word(&mut s.s, "_")?;
+            }
+            i += 1;
+
+            if ty.node != hir::TyInfer {
+                word(&mut s.s, ":")?;
+                space(&mut s.s)?;
+                s.print_type(ty)?;
+            }
+            s.end()
+        })?;
         word(&mut self.s, "|")?;
 
         if let hir::DefaultReturn(..) = decl.output {
@@ -2164,27 +2209,6 @@ impl<'a> State<'a> {
         self.print_type(&mt.ty)
     }
 
-    pub fn print_arg(&mut self, input: &hir::Arg, is_closure: bool) -> io::Result<()> {
-        self.ibox(indent_unit)?;
-        match input.ty.node {
-            hir::TyInfer if is_closure => self.print_pat(&input.pat)?,
-            _ => {
-                let invalid = if let PatKind::Binding(_, _, name, _) = input.pat.node {
-                    name.node == keywords::Invalid.name()
-                } else {
-                    false
-                };
-                if !invalid {
-                    self.print_pat(&input.pat)?;
-                    word(&mut self.s, ":")?;
-                    space(&mut self.s)?;
-                }
-                self.print_type(&input.ty)?;
-            }
-        }
-        self.end()
-    }
-
     pub fn print_fn_output(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
         if let hir::DefaultReturn(..) = decl.output {
             return Ok(());
@@ -2232,7 +2256,9 @@ impl<'a> State<'a> {
                       abi,
                       name,
                       &generics,
-                      &hir::Inherited)?;
+                      &hir::Inherited,
+                      &[],
+                      None)?;
         self.end()
     }
 
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 026f4b187e2..7d8ee33b4be 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -1051,8 +1051,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             Some(ref node) => match *node {
                 ast_map::NodeItem(ref item) => {
                     match item.node {
-                        hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => {
-                            Some((fn_decl, gen, unsafety, constness, item.name, item.span))
+                        hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, body) => {
+                            Some((fn_decl, gen, unsafety, constness, item.name, item.span, body))
                         }
                         _ => None,
                     }
@@ -1066,26 +1066,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             return;
                         }
                     }
-                    if let hir::ImplItemKind::Method(ref sig, _) = item.node {
+                    if let hir::ImplItemKind::Method(ref sig, body) = item.node {
                         Some((&sig.decl,
                               &sig.generics,
                               sig.unsafety,
                               sig.constness,
                               item.name,
-                              item.span))
+                              item.span,
+                              body))
                     } else {
                         None
                     }
                 },
                 ast_map::NodeTraitItem(item) => {
                     match item.node {
-                        hir::TraitItemKind::Method(ref sig, Some(_)) => {
+                        hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
                             Some((&sig.decl,
                                   &sig.generics,
                                   sig.unsafety,
                                   sig.constness,
                                   item.name,
-                                  item.span))
+                                  item.span,
+                                  body))
                         }
                         _ => None,
                     }
@@ -1094,12 +1096,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             },
             None => None,
         };
-        let (fn_decl, generics, unsafety, constness, name, span)
+        let (fn_decl, generics, unsafety, constness, name, span, body)
                                     = node_inner.expect("expect item fn");
         let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver);
         let (fn_decl, generics) = rebuilder.rebuild();
         self.give_expl_lifetime_param(
-            err, &fn_decl, unsafety, constness, name, &generics, span);
+            err, &fn_decl, unsafety, constness, name, &generics, span, body);
     }
 
     pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
@@ -1375,23 +1377,14 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
     }
 
     fn rebuild_args_ty(&self,
-                       inputs: &[hir::Arg],
+                       inputs: &[P<hir::Ty>],
                        lifetime: hir::Lifetime,
                        anon_nums: &HashSet<u32>,
                        region_names: &HashSet<ast::Name>)
-                       -> hir::HirVec<hir::Arg> {
-        let mut new_inputs = Vec::new();
-        for arg in inputs {
-            let new_ty = self.rebuild_arg_ty_or_output(&arg.ty, lifetime,
-                                                       anon_nums, region_names);
-            let possibly_new_arg = hir::Arg {
-                ty: new_ty,
-                pat: arg.pat.clone(),
-                id: arg.id
-            };
-            new_inputs.push(possibly_new_arg);
-        }
-        new_inputs.into()
+                       -> hir::HirVec<P<hir::Ty>> {
+        inputs.iter().map(|arg_ty| {
+            self.rebuild_arg_ty_or_output(arg_ty, lifetime, anon_nums, region_names)
+        }).collect()
     }
 
     fn rebuild_output(&self, ty: &hir::FunctionRetTy,
@@ -1634,10 +1627,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                 constness: hir::Constness,
                                 name: ast::Name,
                                 generics: &hir::Generics,
-                                span: Span) {
-        let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, name, generics);
-        let msg = format!("consider using an explicit lifetime \
-                           parameter as shown: {}", suggested_fn);
+                                span: Span,
+                                body: hir::BodyId) {
+        let s = pprust::fn_decl_in_crate_to_string(self.tcx.map.krate(),
+                                                   decl,
+                                                   unsafety,
+                                                   constness,
+                                                   name,
+                                                   generics,
+                                                   body);
+        let msg = format!("consider using an explicit lifetime parameter as shown: {}", s);
         err.span_help(span, &msg[..]);
     }
 
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 4c2e43f8e22..7dcc5aae8e7 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -140,7 +140,6 @@ pub struct NativeLibrary {
 pub struct InlinedItem {
     pub def_id: DefId,
     pub body: hir::Body,
-    pub const_fn_args: Vec<Option<DefId>>,
 }
 
 /// A borrowed version of `hir::InlinedItem`. This is what's encoded when saving
@@ -149,14 +148,6 @@ pub struct InlinedItem {
 pub struct InlinedItemRef<'a> {
     pub def_id: DefId,
     pub body: &'a hir::Body,
-    pub const_fn_args: Vec<Option<DefId>>,
-}
-
-fn get_fn_args(decl: &hir::FnDecl) -> Vec<Option<DefId>> {
-    decl.inputs.iter().map(|arg| match arg.pat.node {
-        hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
-        _ => None
-    }).collect()
 }
 
 impl<'a, 'tcx> InlinedItemRef<'tcx> {
@@ -164,16 +155,14 @@ impl<'a, 'tcx> InlinedItemRef<'tcx> {
                      item: &hir::Item,
                      tcx: TyCtxt<'a, 'tcx, 'tcx>)
                      -> InlinedItemRef<'tcx> {
-        let (body_id, args) = match item.node {
-            hir::ItemFn(ref decl, _, _, _, _, body_id) =>
-                (body_id, get_fn_args(decl)),
-            hir::ItemConst(_, body_id) => (body_id, vec![]),
+        let body_id = match item.node {
+            hir::ItemFn(.., body_id) |
+            hir::ItemConst(_, body_id) => body_id,
             _ => bug!("InlinedItemRef::from_item wrong kind")
         };
         InlinedItemRef {
             def_id: def_id,
             body: tcx.map.body(body_id),
-            const_fn_args: args
         }
     }
 
@@ -181,9 +170,8 @@ impl<'a, 'tcx> InlinedItemRef<'tcx> {
                            item: &hir::TraitItem,
                            tcx: TyCtxt<'a, 'tcx, 'tcx>)
                            -> InlinedItemRef<'tcx> {
-        let (body_id, args) = match item.node {
-            hir::TraitItemKind::Const(_, Some(body_id)) =>
-                (body_id, vec![]),
+        let body_id = match item.node {
+            hir::TraitItemKind::Const(_, Some(body_id)) => body_id,
             hir::TraitItemKind::Const(_, None) => {
                 bug!("InlinedItemRef::from_trait_item called for const without body")
             },
@@ -192,7 +180,6 @@ impl<'a, 'tcx> InlinedItemRef<'tcx> {
         InlinedItemRef {
             def_id: def_id,
             body: tcx.map.body(body_id),
-            const_fn_args: args
         }
     }
 
@@ -200,17 +187,14 @@ impl<'a, 'tcx> InlinedItemRef<'tcx> {
                           item: &hir::ImplItem,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>)
                           -> InlinedItemRef<'tcx> {
-        let (body_id, args) = match item.node {
-            hir::ImplItemKind::Method(ref sig, body_id) =>
-                (body_id, get_fn_args(&sig.decl)),
-            hir::ImplItemKind::Const(_, body_id) =>
-                (body_id, vec![]),
+        let body_id = match item.node {
+            hir::ImplItemKind::Method(_, body_id) |
+            hir::ImplItemKind::Const(_, body_id) => body_id,
             _ => bug!("InlinedItemRef::from_impl_item wrong kind")
         };
         InlinedItemRef {
             def_id: def_id,
             body: tcx.map.body(body_id),
-            const_fn_args: args
         }
     }
 
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index 8705393849a..3f2893a9e24 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -160,7 +160,7 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
     }
 }
 
-fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
+fn build_nodeid_to_index(body: Option<&hir::Body>,
                          cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> {
     let mut index = NodeMap();
 
@@ -168,8 +168,8 @@ fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
     // into cfg itself?  i.e. introduce a fn-based flow-graph in
     // addition to the current block-based flow-graph, rather than
     // have to put traversals like this here?
-    if let Some(decl) = decl {
-        add_entries_from_fn_decl(&mut index, decl, cfg.entry);
+    if let Some(body) = body {
+        add_entries_from_fn_body(&mut index, body, cfg.entry);
     }
 
     cfg.graph.each_node(|node_idx, node| {
@@ -181,18 +181,22 @@ fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
 
     return index;
 
-    fn add_entries_from_fn_decl(index: &mut NodeMap<Vec<CFGIndex>>,
-                                decl: &hir::FnDecl,
+    /// Add mappings from the ast nodes for the formal bindings to
+    /// the entry-node in the graph.
+    fn add_entries_from_fn_body(index: &mut NodeMap<Vec<CFGIndex>>,
+                                body: &hir::Body,
                                 entry: CFGIndex) {
-        //! add mappings from the ast nodes for the formal bindings to
-        //! the entry-node in the graph.
+        use hir::intravisit::Visitor;
+
         struct Formals<'a> {
             entry: CFGIndex,
             index: &'a mut NodeMap<Vec<CFGIndex>>,
         }
         let mut formals = Formals { entry: entry, index: index };
-        intravisit::walk_fn_decl(&mut formals, decl);
-        impl<'a, 'v> intravisit::Visitor<'v> for Formals<'a> {
+        for arg in &body.arguments {
+            formals.visit_pat(&arg.pat);
+        }
+        impl<'a, 'v> Visitor<'v> for Formals<'a> {
             fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
                 intravisit::NestedVisitorMap::None
             }
@@ -227,7 +231,7 @@ pub enum KillFrom {
 impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                analysis_name: &'static str,
-               decl: Option<&hir::FnDecl>,
+               body: Option<&hir::Body>,
                cfg: &cfg::CFG,
                oper: O,
                id_range: IdRange,
@@ -250,7 +254,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
         let kills2 = zeroes;
         let on_entry = vec![entry; num_nodes * words_per_id];
 
-        let nodeid_to_index = build_nodeid_to_index(decl, cfg);
+        let nodeid_to_index = build_nodeid_to_index(body, cfg);
 
         DataFlowContext {
             tcx: tcx,
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 926975d1423..76adee4e00c 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -333,7 +333,7 @@ impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> {
                     let trait_item = self.krate.trait_item(trait_item_ref.id);
                     match trait_item.node {
                         hir::TraitItemKind::Const(_, Some(_)) |
-                        hir::TraitItemKind::Method(_, Some(_)) => {
+                        hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
                             if has_allow_dead_code_or_lang_attr(&trait_item.attrs) {
                                 self.worklist.push(trait_item.id);
                             }
@@ -573,11 +573,11 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         match trait_item.node {
             hir::TraitItemKind::Const(_, Some(body_id)) |
-            hir::TraitItemKind::Method(_, Some(body_id)) => {
+            hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
                 self.visit_nested_body(body_id)
             }
             hir::TraitItemKind::Const(_, None) |
-            hir::TraitItemKind::Method(_, None) |
+            hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
             hir::TraitItemKind::Type(..) => {}
         }
     }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 1efc4b37ed5..9ba26a0bf1d 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -287,20 +287,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn walk_fn(&mut self,
-                   decl: &hir::FnDecl,
-                   body: &hir::Body) {
-        self.walk_arg_patterns(decl, &body.value);
-        self.consume_expr(&body.value);
-    }
-
-    fn walk_arg_patterns(&mut self,
-                         decl: &hir::FnDecl,
-                         body: &hir::Expr) {
-        for arg in &decl.inputs {
+    pub fn walk_fn(&mut self, body: &hir::Body) {
+        for arg in &body.arguments {
             let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));
 
-            let fn_body_scope_r = self.tcx().node_scope_region(body.id);
+            let fn_body_scope_r = self.tcx().node_scope_region(body.value.id);
             let arg_cmt = self.mc.cat_rvalue(
                 arg.id,
                 arg.pat.span,
@@ -309,6 +300,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
             self.walk_irrefutable_pat(arg_cmt, &arg.pat);
         }
+
+        self.consume_expr(&body.value);
     }
 
     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index ea1c897708b..021cb9bb72d 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -381,7 +381,9 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
 
     debug!("creating fn_maps: {:?}", &fn_maps as *const IrMaps);
 
-    for arg in &decl.inputs {
+    let body = ir.tcx.map.body(body_id);
+
+    for arg in &body.arguments {
         arg.pat.each_binding(|_bm, arg_id, _x, path1| {
             debug!("adding argument {}", arg_id);
             let name = path1.node;
@@ -404,8 +406,6 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
         clean_exit_var: fn_maps.add_variable(CleanExit)
     };
 
-    let body = ir.tcx.map.body(body_id);
-
     // compute liveness
     let mut lsets = Liveness::new(&mut fn_maps, specials);
     let entry_ln = lsets.compute(&body.value);
@@ -413,7 +413,7 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
     // check for various error conditions
     lsets.visit_body(body);
     lsets.check_ret(id, sp, fk, entry_ln, body);
-    lsets.warn_about_unused_args(decl, entry_ln);
+    lsets.warn_about_unused_args(body, entry_ln);
 }
 
 fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
@@ -1502,8 +1502,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         }
     }
 
-    fn warn_about_unused_args(&self, decl: &hir::FnDecl, entry_ln: LiveNode) {
-        for arg in &decl.inputs {
+    fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
+        for arg in &body.arguments {
             arg.pat.each_binding(|_bm, p_id, sp, path1| {
                 let var = self.variable(p_id, sp);
                 // Ignore unused self.
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 34a42dede75..ee841afc021 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -167,7 +167,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             Some(ast_map::NodeTraitItem(trait_method)) => {
                 match trait_method.node {
                     hir::TraitItemKind::Const(_, ref default) => default.is_some(),
-                    hir::TraitItemKind::Method(_, ref body) => body.is_some(),
+                    hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true,
+                    hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
                     hir::TraitItemKind::Type(..) => false,
                 }
             }
@@ -275,11 +276,11 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             ast_map::NodeTraitItem(trait_method) => {
                 match trait_method.node {
                     hir::TraitItemKind::Const(_, None) |
-                    hir::TraitItemKind::Method(_, None) => {
+                    hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => {
                         // Keep going, nothing to get exported
                     }
                     hir::TraitItemKind::Const(_, Some(body_id)) |
-                    hir::TraitItemKind::Method(_, Some(body_id)) => {
+                    hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
                         self.visit_nested_body(body_id);
                     }
                     hir::TraitItemKind::Type(..) => {}
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 9b70c522362..140beefb020 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -190,7 +190,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         // Items always introduce a new root scope
         self.with(RootScope, |_, this| {
             match item.node {
-                hir::ForeignItemFn(ref decl, ref generics) => {
+                hir::ForeignItemFn(ref decl, _, ref generics) => {
                     this.visit_early_late(item.id, decl, generics, |this| {
                         intravisit::walk_foreign_item(this, item);
                     })
@@ -266,7 +266,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         // methods in an impl can reuse label names.
         let saved = replace(&mut self.labels_in_fn, vec![]);
 
-        if let hir::TraitItemKind::Method(ref sig, None) = trait_item.node {
+        if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) =
+                trait_item.node {
             self.visit_early_late(
                 trait_item.id,
                 &sig.decl, &sig.generics,
@@ -860,8 +861,8 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
     debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics);
 
     let mut constrained_by_input = ConstrainedCollector { regions: FxHashSet() };
-    for arg in &decl.inputs {
-        constrained_by_input.visit_ty(&arg.ty);
+    for arg_ty in &decl.inputs {
+        constrained_by_input.visit_ty(arg_ty);
     }
 
     let mut appears_in_output = AllCollector {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 28192cd1873..b03a432de41 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1225,7 +1225,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         // Use call-site for extent (unless this is a
                         // trait method with no default; then fallback
                         // to the method id).
-                        let extent = if let Some(body_id) = *body {
+                        let extent = if let hir::TraitMethod::Provided(body_id) = *body {
                             // default impl: use call_site extent as free_id_outlive bound.
                             tcx.region_maps.call_site_extent(id, body_id.node_id)
                         } else {
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index e5b764be879..f7249784dba 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -189,7 +189,6 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                      move_data: &move_data::FlowedMoveData<'c, 'tcx>,
                                      all_loans: &[Loan<'tcx>],
                                      fn_id: ast::NodeId,
-                                     decl: &hir::FnDecl,
                                      body: &hir::Body) {
     debug!("check_loans(body id={})", body.value.id);
 
@@ -202,7 +201,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         all_loans: all_loans,
         param_env: &infcx.parameter_environment
     };
-    euv::ExprUseVisitor::new(&mut clcx, &infcx).walk_fn(decl, body);
+    euv::ExprUseVisitor::new(&mut clcx, &infcx).walk_fn(body);
 }
 
 #[derive(PartialEq)]
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 50b276ce694..c9e526202fa 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -41,7 +41,6 @@ mod move_error;
 
 pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                     fn_id: NodeId,
-                                    decl: &hir::FnDecl,
                                     body: &hir::Body)
                                     -> (Vec<Loan<'tcx>>,
                                         move_data::MoveData<'tcx>) {
@@ -55,7 +54,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 
     let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
     let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
-    euv::ExprUseVisitor::new(&mut glcx, &infcx).walk_fn(decl, body);
+    euv::ExprUseVisitor::new(&mut glcx, &infcx).walk_fn(body);
 
     glcx.report_potential_errors();
     let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 93c12fed1de..1ba313015d5 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -179,7 +179,7 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
     let AnalysisData { all_loans,
                        loans: loan_dfcx,
                        move_data: flowed_moves } =
-        build_borrowck_dataflow_data(this, fk, decl, &cfg, body, sp, id);
+        build_borrowck_dataflow_data(this, &cfg, body, id);
 
     move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
                                                     this.tcx,
@@ -194,31 +194,31 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                              &flowed_moves,
                              &all_loans[..],
                              id,
-                             decl,
                              body);
 
     intravisit::walk_fn(this, fk, decl, body_id, sp, id);
 }
 
 fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
-                                          fk: FnKind<'tcx>,
-                                          decl: &'tcx hir::FnDecl,
                                           cfg: &cfg::CFG,
                                           body: &'tcx hir::Body,
-                                          sp: Span,
                                           id: ast::NodeId)
                                           -> AnalysisData<'a, 'tcx>
 {
     // Check the body of fn items.
     let tcx = this.tcx;
-    let id_range = intravisit::compute_id_range_for_fn_body(fk, decl, body.id(), sp, id, &tcx.map);
+    let id_range = {
+        let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.map);
+        visitor.visit_body(body);
+        visitor.result()
+    };
     let (all_loans, move_data) =
-        gather_loans::gather_loans_in_fn(this, id, decl, body);
+        gather_loans::gather_loans_in_fn(this, id, body);
 
     let mut loan_dfcx =
         DataFlowContext::new(this.tcx,
                              "borrowck",
-                             Some(decl),
+                             Some(body),
                              cfg,
                              LoanDataFlowOperator,
                              id_range,
@@ -235,7 +235,6 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                                                       this.tcx,
                                                       cfg,
                                                       id_range,
-                                                      decl,
                                                       body);
 
     AnalysisData { all_loans: all_loans,
@@ -266,11 +265,8 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
     let body = tcx.map.body(fn_parts.body);
 
     let dataflow_data = build_borrowck_dataflow_data(&mut bccx,
-                                                     fn_parts.kind,
-                                                     &fn_parts.decl,
                                                      cfg,
                                                      body,
-                                                     fn_parts.span,
                                                      fn_parts.id);
 
     (bccx, dataflow_data)
@@ -1121,22 +1117,21 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
                     if let Categorization::Local(local_id) = inner_cmt.cat {
                         let parent = self.tcx.map.get_parent_node(local_id);
-                        let opt_fn_decl = FnLikeNode::from_node(self.tcx.map.get(parent))
-                            .map(|fn_like| fn_like.decl());
 
-                        if let Some(fn_decl) = opt_fn_decl {
-                            if let Some(ref arg) = fn_decl.inputs.iter()
-                                .find(|ref arg| arg.pat.id == local_id) {
+                        if let Some(fn_like) = FnLikeNode::from_node(self.tcx.map.get(parent)) {
+                            if let Some(i) = self.tcx.map.body(fn_like.body()).arguments.iter()
+                                                     .position(|arg| arg.pat.id == local_id) {
+                                let arg_ty = &fn_like.decl().inputs[i];
                                 if let hir::TyRptr(
                                     opt_lifetime,
                                     hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) =
-                                    arg.ty.node {
+                                    arg_ty.node {
                                     if let Some(lifetime) = opt_lifetime {
                                         if let Ok(snippet) = self.tcx.sess.codemap()
                                             .span_to_snippet(ty.span) {
                                             if let Ok(lifetime_snippet) = self.tcx.sess.codemap()
                                                 .span_to_snippet(lifetime.span) {
-                                                    db.span_label(arg.ty.span,
+                                                    db.span_label(arg_ty.span,
                                                                   &format!("use `&{} mut {}` \
                                                                             here to make mutable",
                                                                             lifetime_snippet,
@@ -1145,9 +1140,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                                         }
                                     }
                                     else if let Ok(snippet) = self.tcx.sess.codemap()
-                                        .span_to_snippet(arg.ty.span) {
+                                        .span_to_snippet(arg_ty.span) {
                                         if snippet.starts_with("&") {
-                                            db.span_label(arg.ty.span,
+                                            db.span_label(arg_ty.span,
                                                           &format!("use `{}` here to make mutable",
                                                                    snippet.replace("&", "&mut ")));
                                         }
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 6a5ee13bb84..a02aba7208c 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -655,13 +655,12 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
                tcx: TyCtxt<'a, 'tcx, 'tcx>,
                cfg: &cfg::CFG,
                id_range: IdRange,
-               decl: &hir::FnDecl,
                body: &hir::Body)
                -> FlowedMoveData<'a, 'tcx> {
         let mut dfcx_moves =
             DataFlowContext::new(tcx,
                                  "flowed_move_data_moves",
-                                 Some(decl),
+                                 Some(body),
                                  cfg,
                                  MoveDataFlowOperator,
                                  id_range,
@@ -669,7 +668,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
         let mut dfcx_assign =
             DataFlowContext::new(tcx,
                                  "flowed_move_data_assigns",
-                                 Some(decl),
+                                 Some(body),
                                  cfg,
                                  AssignDataFlowOperator,
                                  id_range,
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index cb1d67d01c7..4c1fb90e54c 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -43,39 +43,17 @@ struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
 
 impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_expr(&mut self, _expr: &'tcx hir::Expr) {
-        return // const, static and N in [T; N] - shouldn't contain anything
-    }
-
-    fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
-        if let hir::TraitItemKind::Const(..) = item.node {
-            return // nothing worth match checking in a constant
-        } else {
-            intravisit::walk_trait_item(self, item);
-        }
-    }
-
-    fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(..) = item.node {
-            return // nothing worth match checking in a constant
-        } else {
-            intravisit::walk_impl_item(self, item);
-        }
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
                 b: hir::BodyId, s: Span, id: ast::NodeId) {
-        if let FnKind::Closure(..) = fk {
-            span_bug!(s, "check_match: closure outside of function")
-        }
+        intravisit::walk_fn(self, fk, fd, b, s, id);
 
         MatchVisitor {
             tcx: self.tcx,
             param_env: &ty::ParameterEnvironment::for_item(self.tcx, id)
-        }.visit_fn(fk, fd, b, s, id);
+        }.visit_body(self.tcx.map.body(b));
     }
 }
 
@@ -96,7 +74,7 @@ struct MatchVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
@@ -119,13 +97,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
         self.check_patterns(false, slice::ref_slice(&loc.pat));
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::BodyId, s: Span, n: ast::NodeId) {
-        intravisit::walk_fn(self, fk, fd, b, s, n);
+    fn visit_body(&mut self, body: &'tcx hir::Body) {
+        intravisit::walk_body(self, body);
 
-        for input in &fd.inputs {
-            self.check_irrefutable(&input.pat, true);
-            self.check_patterns(false, slice::ref_slice(&input.pat));
+        for arg in &body.arguments {
+            self.check_irrefutable(&arg.pat, true);
+            self.check_patterns(false, slice::ref_slice(&arg.pat));
         }
     }
 }
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index c42b558830f..e27a0476635 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -870,18 +870,16 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
               callee => signal!(e, CallOn(callee)),
           };
-          let (arg_defs, body) = match lookup_const_fn_by_id(tcx, did) {
-              Some(ConstFnNode::Inlined(ii)) => (ii.const_fn_args.clone(), &ii.body),
-              Some(ConstFnNode::Local(fn_like)) =>
-                  (fn_like.decl().inputs.iter()
-                   .map(|arg| match arg.pat.node {
-                       hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
-                       _ => None
-                   }).collect(),
-                   tcx.map.body(fn_like.body())),
+          let body = match lookup_const_fn_by_id(tcx, did) {
+              Some(ConstFnNode::Inlined(ii)) => &ii.body,
+              Some(ConstFnNode::Local(fn_like)) => tcx.map.body(fn_like.body()),
               None => signal!(e, NonConstPath),
           };
-          let result = &body.value;
+
+          let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
+               hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
+               _ => None
+           }).collect::<Vec<_>>();
           assert_eq!(arg_defs.len(), args.len());
 
           let mut call_args = DefIdMap();
@@ -899,7 +897,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               }
           }
           debug!("const call({:?})", call_args);
-          eval_const_expr_partial(tcx, result, ty_hint, Some(&call_args))?
+          eval_const_expr_partial(tcx, &body.value, ty_hint, Some(&call_args))?
       },
       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
           Ok(val) => val,
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 11ade150d1c..4bb12667bbc 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -476,8 +476,10 @@ enum SawTraitOrImplItemComponent {
 fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent {
     match *ti {
         TraitItemKind::Const(..) => SawTraitOrImplItemConst,
-        TraitItemKind::Method(ref sig, ref body) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, body.is_some()),
+        TraitItemKind::Method(ref sig, TraitMethod::Required(_)) =>
+            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false),
+        TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) =>
+            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
         TraitItemKind::Type(..) => SawTraitOrImplItemType
     }
 }
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 5354233e57c..2baef47c214 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -271,12 +271,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
         }
     }
 
-    fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
-        if let hir::TraitItemKind::Method(_, None) = trait_item.node {
+    fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
+        if let hir::TraitItemKind::Method(_, hir::TraitMethod::Required(ref names)) = item.node {
             self.check_snake_case(cx,
                                   "trait method",
-                                  &trait_item.name.as_str(),
-                                  Some(trait_item.span));
+                                  &item.name.as_str(),
+                                  Some(item.span));
+            for name in names {
+                self.check_snake_case(cx, "variable", &name.node.as_str(), Some(name.span));
+            }
         }
     }
 
@@ -288,14 +291,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
     }
 
     fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
-        // Exclude parameter names from foreign functions
-        let parent_node = cx.tcx.map.get_parent_node(p.id);
-        if let hir::map::NodeForeignItem(item) = cx.tcx.map.get(parent_node) {
-            if let hir::ForeignItemFn(..) = item.node {
-                return;
-            }
-        }
-
         if let &PatKind::Binding(_, _, ref path1, _) = &p.node {
             self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span));
         }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 501da680728..c021ffee818 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -240,11 +240,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
         }
     }
 
-    fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
-        if let hir::TraitItemKind::Method(ref sig, None) = trait_item.node {
+    fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
+        if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node {
             if sig.unsafety == hir::Unsafety::Unsafe {
                 cx.span_lint(UNSAFE_CODE,
-                             trait_item.span,
+                             item.span,
                              "declaration of an `unsafe` method")
             }
         }
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 751c9c3440f..a3aa4af493a 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -679,7 +679,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         let sig = self.cx.tcx.erase_late_bound_regions(&sig);
 
         for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
-            self.check_type_for_ffi_and_report_errors(input_hir.ty.span, input_ty);
+            self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
         }
 
         if let hir::Return(ref ret_hir) = decl.output {
@@ -713,7 +713,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
             if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic {
                 for ni in &nmod.items {
                     match ni.node {
-                        hir::ForeignItemFn(ref decl, _) => {
+                        hir::ForeignItemFn(ref decl, _, _) => {
                             vis.check_foreign_fn(ni.id, decl);
                         }
                         hir::ForeignItemStatic(ref ty, _) => {
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index b4c9a0672b0..b7ee688117d 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -97,11 +97,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut {
     fn check_fn(&mut self,
                 cx: &LateContext,
                 _: FnKind,
-                decl: &hir::FnDecl,
-                _: &hir::Body,
+                _: &hir::FnDecl,
+                body: &hir::Body,
                 _: Span,
                 _: ast::NodeId) {
-        for a in &decl.inputs {
+        for a in &body.arguments {
             self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
         }
     }
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 6132b23c720..6a626e9942c 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -128,7 +128,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
 
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>
     {
-        self.dep_graph.read(DepNode::MetaData(did));
+        // FIXME(#38501) We've skipped a `read` on the `HirBody` of
+        // a `fn` when encoding, so the dep-tracking wouldn't work.
+        // This is only used by rustdoc anyway, which shouldn't have
+        // incremental recompilation ever enabled.
+        assert!(!self.dep_graph.is_fully_enabled());
         self.get_crate_data(did.krate).get_fn_arg_names(did.index)
     }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 1c4225817a9..732887620cf 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -34,6 +34,7 @@ use std::io::Cursor;
 use std::rc::Rc;
 use std::u32;
 use syntax::ast::{self, CRATE_NODE_ID};
+use syntax::codemap::Spanned;
 use syntax::attr;
 use syntax::symbol::Symbol;
 use syntax_pos;
@@ -442,10 +443,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let kind = match trait_item.kind {
             ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
             ty::AssociatedKind::Method => {
-                let fn_data = if let hir::TraitItemKind::Method(ref sig, _) = ast_item.node {
+                let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node {
+                    let arg_names = match *m {
+                        hir::TraitMethod::Required(ref names) => {
+                            self.encode_fn_arg_names(names)
+                        }
+                        hir::TraitMethod::Provided(body) => {
+                            self.encode_fn_arg_names_for_body(body)
+                        }
+                    };
                     FnData {
                         constness: hir::Constness::NotConst,
-                        arg_names: self.encode_fn_arg_names(&sig.decl),
+                        arg_names: arg_names
                     }
                 } else {
                     bug!()
@@ -518,10 +527,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let kind = match impl_item.kind {
             ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
             ty::AssociatedKind::Method => {
-                let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+                let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
                     FnData {
                         constness: sig.constness,
-                        arg_names: self.encode_fn_arg_names(&sig.decl),
+                        arg_names: self.encode_fn_arg_names_for_body(body),
                     }
                 } else {
                     bug!()
@@ -574,16 +583,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
-    fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) -> LazySeq<ast::Name> {
-        self.lazy_seq(decl.inputs.iter().map(|arg| {
-            if let PatKind::Binding(_, _, ref path1, _) = arg.pat.node {
-                path1.node
-            } else {
-                Symbol::intern("")
+    fn encode_fn_arg_names_for_body(&mut self, body_id: hir::BodyId)
+                                    -> LazySeq<ast::Name> {
+        let _ignore = self.tcx.dep_graph.in_ignore();
+        let body = self.tcx.map.body(body_id);
+        self.lazy_seq(body.arguments.iter().map(|arg| {
+            match arg.pat.node {
+                PatKind::Binding(_, _, name, _) => name.node,
+                _ => Symbol::intern("")
             }
         }))
     }
 
+    fn encode_fn_arg_names(&mut self, names: &[Spanned<ast::Name>])
+                           -> LazySeq<ast::Name> {
+        self.lazy_seq(names.iter().map(|name| name.node))
+    }
+
     fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Mir<'tcx>>> {
         self.tcx.mir_map.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
     }
@@ -619,10 +635,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
             hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
             hir::ItemConst(..) => EntryKind::Const,
-            hir::ItemFn(ref decl, _, constness, ..) => {
+            hir::ItemFn(_, _, constness, .., body) => {
                 let data = FnData {
                     constness: constness,
-                    arg_names: self.encode_fn_arg_names(&decl),
+                    arg_names: self.encode_fn_arg_names_for_body(body),
                 };
 
                 EntryKind::Fn(self.lazy(&data))
@@ -915,10 +931,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         debug!("writing foreign item {}", tcx.node_path_str(nitem.id));
 
         let kind = match nitem.node {
-            hir::ForeignItemFn(ref fndecl, _) => {
+            hir::ForeignItemFn(_, ref names, _) => {
                 let data = FnData {
                     constness: hir::Constness::NotConst,
-                    arg_names: self.encode_fn_arg_names(&fndecl),
+                    arg_names: self.encode_fn_arg_names(names),
                 };
                 EntryKind::ForeignFn(self.lazy(&data))
             }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index e06d940de7e..63bb1bf20c0 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -729,7 +729,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             name: Some(name),
             source_info: Some(source_info),
         });
-        let extent = self.extent_of_innermost_scope();
+        let extent = self.hir.tcx().region_maps.var_scope(var_id);
         self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty);
         self.var_indices.insert(var_id, var);
 
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 7eefcdb15d0..cfdc1bf27df 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -126,7 +126,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                                        arguments: A,
                                        abi: Abi,
                                        return_ty: Ty<'gcx>,
-                                       body_id: hir::BodyId)
+                                       body: &'gcx hir::Body)
                                        -> Mir<'tcx>
     where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
 {
@@ -138,15 +138,14 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
 
     let call_site_extent =
         tcx.region_maps.lookup_code_extent(
-            CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id.node_id });
+            CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body.value.id });
     let arg_extent =
         tcx.region_maps.lookup_code_extent(
-            CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id.node_id });
+            CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.value.id });
     let mut block = START_BLOCK;
     unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
         unpack!(block = builder.in_scope(arg_extent, block, |builder| {
-            let ast_expr = &tcx.map.body(body_id).value;
-            builder.args_and_body(block, &arguments, arg_extent, ast_expr)
+            builder.args_and_body(block, &arguments, arg_extent, &body.value)
         }));
         // Attribute epilogue to function's closing brace
         let fn_end = Span { lo: span.hi, ..span };
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index c02a1822d73..59a11782e08 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -253,7 +253,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             f: F)
         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>)
     {
-        let extent = self.extent_of_innermost_scope();
+        let extent = self.scopes.last().map(|scope| scope.extent).unwrap();
         let loop_scope = LoopScope {
             extent: extent.clone(),
             continue_block: loop_block,
@@ -411,10 +411,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn extent_of_innermost_scope(&self) -> CodeExtent {
-        self.scopes.last().map(|scope| scope.extent).unwrap()
-    }
-
     /// Returns the extent of the scope which should be exited by a
     /// return.
     pub fn extent_of_return_scope(&self) -> CodeExtent {
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 607411684e7..cbc53ea3c51 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -234,8 +234,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
             (self.tcx.item_type(def_id).fn_abi(), None)
         };
 
+        let body = self.tcx.map.body(body_id);
         let explicit_arguments =
-            decl.inputs
+            body.arguments
                 .iter()
                 .enumerate()
                 .map(|(index, arg)| {
@@ -244,7 +245,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
 
         let arguments = implicit_argument.into_iter().chain(explicit_arguments);
         self.cx(MirSource::Fn(id)).build(|cx| {
-            build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body_id)
+            build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
         });
 
         intravisit::walk_fn(self, fk, decl, body_id, span, id);
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 10983aab309..11f39a8fdf8 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -166,7 +166,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
 
         let qualif = self.with_mode(mode, |this| {
             let body = this.tcx.map.body(b);
-            this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, body));
+            this.with_euv(Some(fn_id), |euv| euv.walk_fn(body));
             intravisit::walk_fn(this, fk, fd, b, s, fn_id);
             this.qualif
         });
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
index e845115cf4f..e4151a66c31 100644
--- a/src/librustc_passes/rvalues.rs
+++ b/src/librustc_passes/rvalues.rs
@@ -52,7 +52,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
             };
             let body = infcx.tcx.map.body(b);
             let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
-            euv.walk_fn(fd, body);
+            euv.walk_fn(body);
         });
         intravisit::walk_fn(self, fk, fd, b, s, fn_id)
     }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 3b2520308c7..5c49ace4917 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -227,6 +227,7 @@ pub fn ast_region_to_region<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 }
 
 fn report_elision_failure(
+    tcx: TyCtxt,
     db: &mut DiagnosticBuilder,
     params: Vec<ElisionFailureInfo>)
 {
@@ -241,13 +242,14 @@ fn report_elision_failure(
 
     for (i, info) in elided_params.into_iter().enumerate() {
         let ElisionFailureInfo {
-            name, lifetime_count: n, have_bound_regions
+            parent, index, lifetime_count: n, have_bound_regions
         } = info;
 
-        let help_name = if name.is_empty() {
-            format!("argument {}", i + 1)
+        let help_name = if let Some(body) = parent {
+            let arg = &tcx.map.body(body).arguments[index];
+            format!("`{}`", pprust::pat_to_string(&arg.pat))
         } else {
-            format!("`{}`", name)
+            format!("argument {}", index + 1)
         };
 
         m.push_str(&(if n == 1 {
@@ -315,7 +317,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     err.span_label(ampersand_span, &format!("expected lifetime parameter"));
 
                     if let Some(params) = params {
-                        report_elision_failure(&mut err, params);
+                        report_elision_failure(self.tcx(), &mut err, params);
                     }
                     err.emit();
                     ty::ReStatic
@@ -540,15 +542,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     /// corresponding to each input type/pattern.
     fn find_implied_output_region<I>(&self,
                                      input_tys: &[Ty<'tcx>],
-                                     input_pats: I) -> ElidedLifetime
-        where I: Iterator<Item=String>
+                                     parent: Option<hir::BodyId>,
+                                     input_indices: I) -> ElidedLifetime
+        where I: Iterator<Item=usize>
     {
         let tcx = self.tcx();
         let mut lifetimes_for_params = Vec::with_capacity(input_tys.len());
         let mut possible_implied_output_region = None;
         let mut lifetimes = 0;
 
-        for input_type in input_tys.iter() {
+        for (input_type, index) in input_tys.iter().zip(input_indices) {
             let mut regions = FxHashSet();
             let have_bound_regions = tcx.collect_regions(input_type, &mut regions);
 
@@ -564,11 +567,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 possible_implied_output_region = regions.iter().cloned().next();
             }
 
-            // Use a placeholder for `name` because computing it can be
-            // expensive and we don't want to do it until we know it's
-            // necessary.
             lifetimes_for_params.push(ElisionFailureInfo {
-                name: String::new(),
+                parent: parent,
+                index: index,
                 lifetime_count: regions.len(),
                 have_bound_regions: have_bound_regions
             });
@@ -577,11 +578,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         if lifetimes == 1 {
             Ok(*possible_implied_output_region.unwrap())
         } else {
-            // Fill in the expensive `name` fields now that we know they're
-            // needed.
-            for (info, input_pat) in lifetimes_for_params.iter_mut().zip(input_pats) {
-                info.name = input_pat;
-            }
             Err(Some(lifetimes_for_params))
         }
     }
@@ -618,8 +614,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| {
             self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t)
         }));
-        let input_params = iter::repeat(String::new()).take(inputs.len());
-        let implied_output_region = self.find_implied_output_region(&inputs, input_params);
+        let input_params = 0..inputs.len();
+        let implied_output_region = self.find_implied_output_region(&inputs, None, input_params);
 
         let (output, output_span) = match data.output {
             Some(ref output_ty) => {
@@ -1572,6 +1568,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                                               bf.abi,
                                                               None,
                                                               &bf.decl,
+                                                              None,
                                                               anon_scope,
                                                               anon_scope);
 
@@ -1696,26 +1693,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
     pub fn ty_of_arg(&self,
                      rscope: &RegionScope,
-                     a: &hir::Arg,
+                     ty: &hir::Ty,
                      expected_ty: Option<Ty<'tcx>>)
                      -> Ty<'tcx>
     {
-        match a.ty.node {
+        match ty.node {
             hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
-            hir::TyInfer => self.ty_infer(a.ty.span),
-            _ => self.ast_ty_to_ty(rscope, &a.ty),
+            hir::TyInfer => self.ty_infer(ty.span),
+            _ => self.ast_ty_to_ty(rscope, ty),
         }
     }
 
     pub fn ty_of_method(&self,
                         sig: &hir::MethodSig,
                         opt_self_value_ty: Option<Ty<'tcx>>,
+                        body: Option<hir::BodyId>,
                         anon_scope: Option<AnonTypeScope>)
                         -> &'tcx ty::BareFnTy<'tcx> {
         self.ty_of_method_or_bare_fn(sig.unsafety,
                                      sig.abi,
                                      opt_self_value_ty,
                                      &sig.decl,
+                                     body,
                                      None,
                                      anon_scope)
     }
@@ -1724,9 +1723,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                          unsafety: hir::Unsafety,
                          abi: abi::Abi,
                          decl: &hir::FnDecl,
+                         body: hir::BodyId,
                          anon_scope: Option<AnonTypeScope>)
                          -> &'tcx ty::BareFnTy<'tcx> {
-        self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope)
+        self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, Some(body), None, anon_scope)
     }
 
     fn ty_of_method_or_bare_fn(&self,
@@ -1734,6 +1734,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                abi: abi::Abi,
                                opt_self_value_ty: Option<Ty<'tcx>>,
                                decl: &hir::FnDecl,
+                               body: Option<hir::BodyId>,
                                arg_anon_scope: Option<AnonTypeScope>,
                                ret_anon_scope: Option<AnonTypeScope>)
                                -> &'tcx ty::BareFnTy<'tcx>
@@ -1764,12 +1765,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             // reference) in the arguments, then any anonymous regions in the output
             // have that lifetime.
             _ => {
-                let arg_params = &decl.inputs[has_self as usize..];
                 let arg_tys = &input_tys[has_self as usize..];
-
-                self.find_implied_output_region(arg_tys,
-                                                arg_params.iter()
-                                                    .map(|a| pprust::pat_to_string(&a.pat)))
+                let arg_params = has_self as usize..input_tys.len();
+                self.find_implied_output_region(arg_tys, body, arg_params)
 
             }
         };
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 0a18aad2712..be10b77bd8b 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -456,7 +456,7 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                 };
 
                 impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
-                    match (&impl_arg.ty.node, &trait_arg.ty.node) {
+                    match (&impl_arg.node, &trait_arg.node) {
                         (&hir::TyRptr(_, ref impl_mt), &hir::TyRptr(_, ref trait_mt)) |
                         (&hir::TyPtr(ref impl_mt), &hir::TyPtr(ref trait_mt)) => {
                             impl_mt.mutbl != trait_mt.mutbl
@@ -464,7 +464,7 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                         _ => false,
                     }
                 }).map(|(ref impl_arg, ref trait_arg)| {
-                    (impl_arg.ty.span, Some(trait_arg.ty.span))
+                    (impl_arg.span, Some(trait_arg.span))
                 })
                 .unwrap_or_else(|| (cause.span, tcx.map.span_if_local(trait_m.def_id)))
             } else {
@@ -489,7 +489,7 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                          .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
                              match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) {
                                  Ok(_) => None,
-                                 Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
+                                 Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
                              }
                          })
                          .next()
@@ -680,7 +680,7 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     } else {
                         0
                     }) {
-                        Some(arg.pat.span)
+                        Some(arg.span)
                     } else {
                         trait_item_span
                     }
@@ -698,7 +698,7 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 } else {
                     0
                 }) {
-                    arg.pat.span
+                    arg.span
                 } else {
                     impl_m_span
                 }
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 183a2a48ff5..c733c0856c6 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -48,7 +48,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let i_n_tps = tcx.item_generics(def_id).types.len();
     if i_n_tps != n_tps {
         let span = match it.node {
-            hir::ForeignItemFn(_, ref generics) => generics.span,
+            hir::ForeignItemFn(_, _, ref generics) => generics.span,
             hir::ForeignItemStatic(..) => it.span
         };
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 021aeec47f0..e919075bc8f 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -681,8 +681,8 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         fcx.check_casts();
         fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
 
-        fcx.regionck_fn(fn_id, decl, body);
-        fcx.resolve_type_vars_in_fn(decl, body, fn_id);
+        fcx.regionck_fn(fn_id, body);
+        fcx.resolve_type_vars_in_body(body, fn_id);
     });
 }
 
@@ -751,16 +751,6 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
         intravisit::walk_pat(self, p);
     }
 
-    fn visit_ty(&mut self, t: &'gcx hir::Ty) {
-        match t.node {
-            hir::TyBareFn(ref function_declaration) => {
-                intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
-                walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
-            }
-            _ => intravisit::walk_ty(self, t)
-        }
-    }
-
     // Don't descend into the bodies of nested closures
     fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
                 _: hir::BodyId, _: Span, _: ast::NodeId) { }
@@ -796,31 +786,21 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty.unwrap(),
                                fn_sig.variadic);
 
-    {
-        let mut visit = GatherLocalsVisitor { fcx: &fcx, };
-
-        // Add formal parameters.
-        for (arg_ty, input) in fn_sig.inputs().iter().zip(&decl.inputs) {
-            // The type of the argument must be well-formed.
-            //
-            // NB -- this is now checked in wfcheck, but that
-            // currently only results in warnings, so we issue an
-            // old-style WF obligation here so that we still get the
-            // errors that we used to get.
-            fcx.register_old_wf_obligation(arg_ty, input.ty.span, traits::MiscObligation);
-
-            // Create type variables for each argument.
-            input.pat.each_binding(|_bm, pat_id, sp, _path| {
-                let var_ty = visit.assign(sp, pat_id, None);
-                fcx.require_type_is_sized(var_ty, sp, traits::VariableType(pat_id));
-            });
+    GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
 
-            // Check the pattern.
-            fcx.check_pat(&input.pat, arg_ty);
-            fcx.write_ty(input.id, arg_ty);
-        }
+    // Add formal parameters.
+    for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
+        // The type of the argument must be well-formed.
+        //
+        // NB -- this is now checked in wfcheck, but that
+        // currently only results in warnings, so we issue an
+        // old-style WF obligation here so that we still get the
+        // errors that we used to get.
+        fcx.register_old_wf_obligation(arg_ty, arg.pat.span, traits::MiscObligation);
 
-        visit.visit_body(body);
+        // Check the pattern.
+        fcx.check_pat(&arg.pat, arg_ty);
+        fcx.write_ty(arg.id, arg_ty);
     }
 
     inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
@@ -910,7 +890,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                     err.emit();
                 }
 
-                if let hir::ForeignItemFn(ref fn_decl, _) = item.node {
+                if let hir::ForeignItemFn(ref fn_decl, _, _) = item.node {
                     require_c_abi_if_variadic(ccx.tcx, fn_decl, m.abi, item.span);
                 }
             }
@@ -954,10 +934,10 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                 hir::TraitItemKind::Const(_, Some(expr)) => {
                     check_const(ccx, expr, trait_item.id)
                 }
-                hir::TraitItemKind::Method(ref sig, Some(body_id)) => {
+                hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body_id)) => {
                     check_bare_fn(ccx, &sig.decl, body_id, trait_item.id, trait_item.span);
                 }
-                hir::TraitItemKind::Method(_, None) |
+                hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
                 hir::TraitItemKind::Const(_, None) |
                 hir::TraitItemKind::Type(..) => {
                     // Nothing to do.
@@ -1269,7 +1249,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
         fcx.select_all_obligations_or_error();
 
         fcx.regionck_expr(body);
-        fcx.resolve_type_vars_in_expr(body, id);
+        fcx.resolve_type_vars_in_body(body, id);
     });
 }
 
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 80b967210f9..bd63eb6ad25 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -141,7 +141,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn regionck_fn(&self,
                        fn_id: ast::NodeId,
-                       decl: &hir::FnDecl,
                        body: &'gcx hir::Body) {
         debug!("regionck_fn(id={})", fn_id);
         let node_id = body.value.id;
@@ -149,7 +148,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if self.err_count_since_creation() == 0 {
             // regionck assumes typeck succeeded
-            rcx.visit_fn_body(fn_id, decl, body, self.tcx.map.span(fn_id));
+            rcx.visit_fn_body(fn_id, body, self.tcx.map.span(fn_id));
         }
 
         rcx.free_region_map.relate_free_regions_from_predicates(
@@ -268,7 +267,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
     fn visit_fn_body(&mut self,
                      id: ast::NodeId, // the id of the fn itself
-                     fn_decl: &hir::FnDecl,
                      body: &'gcx hir::Body,
                      span: Span)
     {
@@ -303,8 +301,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         let old_body_id = self.set_body_id(body_id.node_id);
         self.relate_free_regions(&fn_sig_tys[..], body_id.node_id, span);
-        self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id),
-                          &fn_decl.inputs[..]);
+        self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id), &body.arguments);
         self.visit_body(body);
         self.visit_region_obligations(body_id.node_id);
 
@@ -483,10 +480,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
         NestedVisitorMap::None
     }
 
-    fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, fd: &'gcx hir::FnDecl,
+    fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
                 b: hir::BodyId, span: Span, id: ast::NodeId) {
         let body = self.tcx.map.body(b);
-        self.visit_fn_body(id, fd, body, span)
+        self.visit_fn_body(id, body, span)
     }
 
     //visit_pat: visit_pat, // (..) see above
@@ -1116,7 +1113,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         for arg in args {
             let arg_ty = self.node_ty(arg.id);
             let re_scope = self.tcx.mk_region(ty::ReScope(body_scope));
-            let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
+            let arg_cmt = mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty);
             debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
                    arg_ty,
                    arg_cmt,
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 0ad01a0e00d..af4fe2dc41b 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -157,7 +157,6 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
     fn analyze_closure(&mut self,
                        id: ast::NodeId,
                        span: Span,
-                       decl: &hir::FnDecl,
                        body: &hir::Body) {
         /*!
          * Analysis starting point.
@@ -172,7 +171,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                                                   mc::MemCategorizationOptions {
                                                       during_closure_kind_inference: true
                                                   });
-            euv.walk_fn(decl, body);
+            euv.walk_fn(body);
         }
 
         // Now that we've analyzed the closure, we know how each
@@ -505,7 +504,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
 
         let body = self.fcx.tcx.map.body(body);
         self.visit_body(body);
-        self.analyze_closure(id, span, decl, body);
+        self.analyze_closure(id, span, body);
     }
 }
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 4955322963a..c80db7fa4d0 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -478,7 +478,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             return;
         }
 
-        let span = method_sig.decl.inputs[0].pat.span;
+        let span = method_sig.decl.inputs[0].span;
 
         let free_substs = &fcx.parameter_environment.free_substs;
         let method_ty = fcx.tcx.item_type(method.def_id);
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index beed85297fd..479d595ee73 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -28,40 +28,21 @@ use syntax_pos::Span;
 
 use rustc::hir::print::pat_to_string;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::hir::{self, PatKind};
+use rustc::hir;
 
 ///////////////////////////////////////////////////////////////////////////
-// Entry point functions
+// Entry point
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn resolve_type_vars_in_expr(&self, body: &'gcx hir::Body, item_id: ast::NodeId) {
+    pub fn resolve_type_vars_in_body(&self,
+                                     body: &'gcx hir::Body,
+                                     item_id: ast::NodeId) {
         assert_eq!(self.writeback_errors.get(), false);
         let mut wbcx = WritebackCx::new(self);
-        wbcx.visit_body(body);
-        wbcx.visit_upvar_borrow_map();
-        wbcx.visit_closures();
-        wbcx.visit_liberated_fn_sigs();
-        wbcx.visit_fru_field_types();
-        wbcx.visit_deferred_obligations(item_id);
-        wbcx.visit_type_nodes();
-    }
-
-    pub fn resolve_type_vars_in_fn(&self,
-                                   decl: &'gcx hir::FnDecl,
-                                   body: &'gcx hir::Body,
-                                   item_id: ast::NodeId) {
-        assert_eq!(self.writeback_errors.get(), false);
-        let mut wbcx = WritebackCx::new(self);
-        wbcx.visit_body(body);
-        for arg in &decl.inputs {
+        for arg in &body.arguments {
             wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
-            wbcx.visit_pat(&arg.pat);
-
-            // Privacy needs the type for the whole pattern, not just each binding
-            if let PatKind::Binding(..) = arg.pat.node {} else {
-                wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.pat.id);
-            }
         }
+        wbcx.visit_body(body);
         wbcx.visit_upvar_borrow_map();
         wbcx.visit_closures();
         wbcx.visit_liberated_fn_sigs();
@@ -211,12 +192,12 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
         self.visit_method_map_entry(ResolvingExpr(e.span),
                                     MethodCall::expr(e.id));
 
-        if let hir::ExprClosure(_, ref decl, body, _) = e.node {
-            for input in &decl.inputs {
-                self.visit_node_id(ResolvingExpr(e.span), input.id);
+        if let hir::ExprClosure(_, _, body, _) = e.node {
+            let body = self.fcx.tcx.map.body(body);
+            for arg in &body.arguments {
+                self.visit_node_id(ResolvingExpr(e.span), arg.id);
             }
 
-            let body = self.fcx.tcx.map.body(body);
             self.visit_body(body);
         }
 
@@ -257,16 +238,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
         self.write_ty_to_tcx(l.id, var_ty);
         intravisit::walk_local(self, l);
     }
-
-    fn visit_ty(&mut self, t: &'gcx hir::Ty) {
-        match t.node {
-            hir::TyBareFn(ref function_declaration) => {
-                intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
-                walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
-            }
-            _ => intravisit::walk_ty(self, t)
-        }
-    }
 }
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index cb9e1c989e3..bbaf1b65110 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -640,7 +640,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             id: ast::NodeId,
                             sig: &hir::MethodSig,
                             untransformed_rcvr_ty: Ty<'tcx>,
-                            rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
+                            body: Option<hir::BodyId>,
+                            rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) {
     let def_id = ccx.tcx.map.local_def_id(id);
     let ty_generics = generics_of_def_id(ccx, def_id);
 
@@ -658,7 +659,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         None
     };
     let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
-                                    sig, self_value_ty, anon_scope);
+                                    sig, self_value_ty, body, anon_scope);
 
     let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
                                 ccx.tcx.map.span(id), def_id);
@@ -865,10 +866,14 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
             convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
         }
 
-        hir::TraitItemKind::Method(ref sig, _) => {
+        hir::TraitItemKind::Method(ref sig, ref method) => {
+            let body = match *method {
+                hir::TraitMethod::Required(_) => None,
+                hir::TraitMethod::Provided(body) => Some(body)
+            };
             convert_method(ccx, TraitContainer(trait_def_id),
                            trait_item.id, sig, tcx.mk_self_type(),
-                           &trait_predicates);
+                           body, &trait_predicates);
         }
     }
 }
@@ -908,10 +913,10 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
             convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
         }
 
-        hir::ImplItemKind::Method(ref sig, _) => {
+        hir::ImplItemKind::Method(ref sig, body) => {
             convert_method(ccx, ImplContainer(impl_def_id),
                            impl_item.id, sig, impl_self_ty,
-                           &impl_predicates);
+                           Some(body), &impl_predicates);
         }
     }
 }
@@ -1429,7 +1434,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             NodeForeignItem(item) => {
                 match item.node {
                     ForeignItemStatic(..) => &no_generics,
-                    ForeignItemFn(_, ref generics) => generics
+                    ForeignItemFn(_, _, ref generics) => generics
                 }
             }
 
@@ -1530,9 +1535,9 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
                         ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t)
                     }
-                    ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
+                    ItemFn(ref decl, unsafety, _, abi, ref generics, body) => {
                         let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl,
-                                                          Some(AnonTypeScope::new(def_id)));
+                                                          body, Some(AnonTypeScope::new(def_id)));
                         let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
                         ccx.tcx.mk_fn_def(def_id, substs, tofd)
                     }
@@ -1572,7 +1577,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 let abi = ccx.tcx.map.get_foreign_abi(node_id);
 
                 match foreign_item.node {
-                    ForeignItemFn(ref fn_decl, ref generics) => {
+                    ForeignItemFn(ref fn_decl, _, ref generics) => {
                         compute_type_of_foreign_fn_decl(
                             ccx, ccx.tcx.map.local_def_id(foreign_item.id),
                             fn_decl, generics, abi)
@@ -1637,7 +1642,7 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     let no_generics = hir::Generics::empty();
     let generics = match it.node {
-        hir::ForeignItemFn(_, ref generics) => generics,
+        hir::ForeignItemFn(_, _, ref generics) => generics,
         hir::ForeignItemStatic(..) => &no_generics
     };
 
@@ -2073,7 +2078,7 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
             }
         };
         for (input, ty) in decl.inputs.iter().zip(&input_tys) {
-            check(&input.ty, ty)
+            check(&input, ty)
         }
         if let hir::Return(ref ty) = decl.output {
             check(&ty, output)
diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs
index 131ecfc6e0c..3f5e443a20a 100644
--- a/src/librustc_typeck/rscope.rs
+++ b/src/librustc_typeck/rscope.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::ty;
 use rustc::ty::subst::Substs;
@@ -19,7 +20,10 @@ use syntax_pos::Span;
 
 #[derive(Clone)]
 pub struct ElisionFailureInfo {
-    pub name: String,
+    /// Where we can find the argument pattern.
+    pub parent: Option<hir::BodyId>,
+    /// The index of the argument in the original definition.
+    pub index: usize,
     pub lifetime_count: usize,
     pub have_bound_regions: bool
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 40f005fecbd..7516faab519 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1030,22 +1030,14 @@ pub struct Method {
     pub abi: Abi,
 }
 
-impl Clean<Method> for hir::MethodSig {
+impl<'a> Clean<Method> for (&'a hir::MethodSig, hir::BodyId) {
     fn clean(&self, cx: &DocContext) -> Method {
-        let decl = FnDecl {
-            inputs: Arguments {
-                values: self.decl.inputs.clean(cx),
-            },
-            output: self.decl.output.clean(cx),
-            variadic: false,
-            attrs: Attributes::default()
-        };
         Method {
-            generics: self.generics.clean(cx),
-            unsafety: self.unsafety,
-            constness: self.constness,
-            decl: decl,
-            abi: self.abi
+            generics: self.0.generics.clean(cx),
+            unsafety: self.0.unsafety,
+            constness: self.0.constness,
+            decl: (&*self.0.decl, self.1).clean(cx),
+            abi: self.0.abi
         }
     }
 }
@@ -1058,25 +1050,6 @@ pub struct TyMethod {
     pub abi: Abi,
 }
 
-impl Clean<TyMethod> for hir::MethodSig {
-    fn clean(&self, cx: &DocContext) -> TyMethod {
-        let decl = FnDecl {
-            inputs: Arguments {
-                values: self.decl.inputs.clean(cx),
-            },
-            output: self.decl.output.clean(cx),
-            variadic: false,
-            attrs: Attributes::default()
-        };
-        TyMethod {
-            unsafety: self.unsafety.clone(),
-            decl: decl,
-            generics: self.generics.clean(cx),
-            abi: self.abi
-        }
-    }
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Function {
     pub decl: FnDecl,
@@ -1097,7 +1070,7 @@ impl Clean<Item> for doctree::Function {
             deprecation: self.depr.clean(cx),
             def_id: cx.tcx.map.local_def_id(self.id),
             inner: FunctionItem(Function {
-                decl: self.decl.clean(cx),
+                decl: (&self.decl, self.body).clean(cx),
                 generics: self.generics.clean(cx),
                 unsafety: self.unsafety,
                 constness: self.constness,
@@ -1130,14 +1103,47 @@ pub struct Arguments {
     pub values: Vec<Argument>,
 }
 
-impl Clean<FnDecl> for hir::FnDecl {
+impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], &'a [Spanned<ast::Name>]) {
+    fn clean(&self, cx: &DocContext) -> Arguments {
+        Arguments {
+            values: self.0.iter().enumerate().map(|(i, ty)| {
+                let mut name = self.1.get(i).map(|n| n.node.to_string())
+                                            .unwrap_or(String::new());
+                if name.is_empty() {
+                    name = "_".to_string();
+                }
+                Argument {
+                    name: name,
+                    type_: ty.clean(cx),
+                }
+            }).collect()
+        }
+    }
+}
+
+impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], hir::BodyId) {
+    fn clean(&self, cx: &DocContext) -> Arguments {
+        let body = cx.tcx.map.body(self.1);
+
+        Arguments {
+            values: self.0.iter().enumerate().map(|(i, ty)| {
+                Argument {
+                    name: name_from_pat(&body.arguments[i].pat),
+                    type_: ty.clean(cx),
+                }
+            }).collect()
+        }
+    }
+}
+
+impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
+    where (&'a [P<hir::Ty>], A): Clean<Arguments>
+{
     fn clean(&self, cx: &DocContext) -> FnDecl {
         FnDecl {
-            inputs: Arguments {
-                values: self.inputs.clean(cx),
-            },
-            output: self.output.clean(cx),
-            variadic: self.variadic,
+            inputs: (&self.0.inputs[..], self.1).clean(cx),
+            output: self.0.output.clean(cx),
+            variadic: self.0.variadic,
             attrs: Attributes::default()
         }
     }
@@ -1159,7 +1165,6 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
                 values: sig.skip_binder().inputs().iter().map(|t| {
                     Argument {
                         type_: t.clean(cx),
-                        id: ast::CRATE_NODE_ID,
                         name: names.next().map_or("".to_string(), |name| name.to_string()),
                     }
                 }).collect(),
@@ -1172,7 +1177,6 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
 pub struct Argument {
     pub type_: Type,
     pub name: String,
-    pub id: ast::NodeId,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
@@ -1199,16 +1203,6 @@ impl Argument {
     }
 }
 
-impl Clean<Argument> for hir::Arg {
-    fn clean(&self, cx: &DocContext) -> Argument {
-        Argument {
-            name: name_from_pat(&*self.pat),
-            type_: (self.ty.clean(cx)),
-            id: self.id
-        }
-    }
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub enum FunctionRetTy {
     Return(Type),
@@ -1274,11 +1268,16 @@ impl Clean<Item> for hir::TraitItem {
                 AssociatedConstItem(ty.clean(cx),
                                     default.map(|e| print_const_expr(cx, e)))
             }
-            hir::TraitItemKind::Method(ref sig, Some(_)) => {
-                MethodItem(sig.clean(cx))
+            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
+                MethodItem((sig, body).clean(cx))
             }
-            hir::TraitItemKind::Method(ref sig, None) => {
-                TyMethodItem(sig.clean(cx))
+            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
+                TyMethodItem(TyMethod {
+                    unsafety: sig.unsafety.clone(),
+                    decl: (&*sig.decl, &names[..]).clean(cx),
+                    generics: sig.generics.clean(cx),
+                    abi: sig.abi
+                })
             }
             hir::TraitItemKind::Type(ref bounds, ref default) => {
                 AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
@@ -1304,8 +1303,8 @@ impl Clean<Item> for hir::ImplItem {
                 AssociatedConstItem(ty.clean(cx),
                                     Some(print_const_expr(cx, expr)))
             }
-            hir::ImplItemKind::Method(ref sig, _) => {
-                MethodItem(sig.clean(cx))
+            hir::ImplItemKind::Method(ref sig, body) => {
+                MethodItem((sig, body).clean(cx))
             }
             hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
                 type_: ty.clean(cx),
@@ -2343,7 +2342,7 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy {
                 type_params: Vec::new(),
                 where_predicates: Vec::new()
             },
-            decl: self.decl.clean(cx),
+            decl: (&*self.decl, &[][..]).clean(cx),
             abi: self.abi,
         }
     }
@@ -2641,9 +2640,9 @@ impl Clean<Vec<Item>> for hir::ForeignMod {
 impl Clean<Item> for hir::ForeignItem {
     fn clean(&self, cx: &DocContext) -> Item {
         let inner = match self.node {
-            hir::ForeignItemFn(ref decl, ref generics) => {
+            hir::ForeignItemFn(ref decl, ref names, ref generics) => {
                 ForeignFunctionItem(Function {
-                    decl: decl.clean(cx),
+                    decl: (&**decl, &names[..]).clean(cx),
                     generics: generics.clean(cx),
                     unsafety: hir::Unsafety::Unsafe,
                     abi: Abi::Rust,
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 46b1ed2aa24..d819268240b 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -156,6 +156,7 @@ pub struct Function {
     pub whence: Span,
     pub generics: hir::Generics,
     pub abi: abi::Abi,
+    pub body: hir::BodyId,
 }
 
 pub struct Typedef {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 5a90a739de4..b0afc3d63f4 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -157,7 +157,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     unsafety: &hir::Unsafety,
                     constness: hir::Constness,
                     abi: &abi::Abi,
-                    gen: &hir::Generics) -> Function {
+                    gen: &hir::Generics,
+                    body: hir::BodyId) -> Function {
         debug!("Visiting fn");
         Function {
             id: item.id,
@@ -172,6 +173,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             unsafety: *unsafety,
             constness: constness,
             abi: *abi,
+            body: body,
         }
     }
 
@@ -410,9 +412,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 om.structs.push(self.visit_variant_data(item, name, sd, gen)),
             hir::ItemUnion(ref sd, ref gen) =>
                 om.unions.push(self.visit_union_data(item, name, sd, gen)),
-            hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
+            hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, body) =>
                 om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
-                                          constness, abi, gen)),
+                                          constness, abi, gen, body)),
             hir::ItemTy(ref ty, ref gen) => {
                 let t = Typedef {
                     ty: ty.clone(),
diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs
index f8aa1ea95f0..eac134ff3cc 100644
--- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs
+++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs
@@ -14,8 +14,8 @@ struct Foo<'a,'b> {
 }
 
 impl<'a,'b> Foo<'a,'b> {
-    fn bar(
-        self
+    fn bar(self:
+           Foo<'b,'a>
     //~^ ERROR mismatched method receiver
     //~| expected type `Foo<'a, 'b>`
     //~| found type `Foo<'b, 'a>`
@@ -24,7 +24,7 @@ impl<'a,'b> Foo<'a,'b> {
     //~| expected type `Foo<'a, 'b>`
     //~| found type `Foo<'b, 'a>`
     //~| lifetime mismatch
-            : Foo<'b,'a>) {}
+           ) {}
 }
 
 fn main() {}
diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs
index d3793d6cdd8..bc401ae9340 100644
--- a/src/test/incremental/hashes/trait_defs.rs
+++ b/src/test/incremental/hashes/trait_defs.rs
@@ -158,6 +158,7 @@ trait TraitAddParameterToMethod {
 #[cfg(cfail1)]
 trait TraitChangeMethodParameterName {
     fn method(a: u32);
+    fn with_default(x: i32) {}
 }
 
 #[cfg(not(cfail1))]
@@ -166,11 +167,20 @@ trait TraitChangeMethodParameterName {
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterName {
+    // FIXME(#38501) This should preferably always be clean.
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn method(b: u32);
+
+    #[rustc_clean(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_dirty(label="HirBody", cfg="cfail2")]
+    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn with_default(y: i32) {}
 }
 
 
@@ -303,7 +313,7 @@ trait TraitChangeModeSelfOwnToMut: Sized {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeModeSelfOwnToMut: Sized {
     #[rustc_dirty(label="Hir", cfg="cfail2")]