]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/hir/lowering.rs
rustc: async fn drop order lowering in HIR
[rust.git] / src / librustc / hir / lowering.rs
index 90dff5e3fc4b44fdd23f2044e73acfe796e426ea..e82b3df8550357139f7e6f6607ed4f878a50f986 100644 (file)
@@ -50,6 +50,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_data_structures::thin_vec::ThinVec;
+use rustc_data_structures::sync::Lrc;
 
 use std::collections::{BTreeSet, BTreeMap};
 use std::mem;
 use syntax::ast;
 use syntax::ast::*;
 use syntax::errors;
-use syntax::ext::hygiene::Mark;
+use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::print::pprust;
 use syntax::ptr::P;
-use syntax::source_map::{respan, CompilerDesugaringKind, Spanned};
+use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned};
 use syntax::source_map::CompilerDesugaringKind::IfTemporary;
 use syntax::std_inject;
 use syntax::symbol::{kw, sym, Symbol};
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::parse::token::Token;
 use syntax::visit::{self, Visitor};
-use syntax_pos::Span;
+use syntax_pos::{edition, Span};
 
 const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
 
@@ -465,32 +466,6 @@ fn visit_pat(&mut self, p: &'lcx Pat) {
                 visit::walk_pat(self, p)
             }
 
-            fn visit_fn(&mut self, fk: visit::FnKind<'lcx>, fd: &'lcx FnDecl, s: Span, _: NodeId) {
-                if fk.header().map(|h| h.asyncness.node.is_async()).unwrap_or(false) {
-                    // Don't visit the original pattern for async functions as it will be
-                    // replaced.
-                    for arg in &fd.inputs {
-                        if let ArgSource::AsyncFn(pat) = &arg.source { self.visit_pat(pat); }
-                        self.visit_ty(&arg.ty)
-                    }
-                    self.visit_fn_ret_ty(&fd.output);
-
-                    match fk {
-                        visit::FnKind::ItemFn(_, decl, _, body) => {
-                            self.visit_fn_header(decl);
-                            self.visit_block(body)
-                        },
-                        visit::FnKind::Method(_, sig, _, body) => {
-                            self.visit_fn_header(&sig.header);
-                            self.visit_block(body)
-                        },
-                        visit::FnKind::Closure(body) => self.visit_expr(body),
-                    }
-                } else {
-                    visit::walk_fn(self, fk, fd, s)
-                }
-            }
-
             fn visit_item(&mut self, item: &'lcx Item) {
                 let hir_id = self.lctx.allocate_hir_id_counter(item.id);
 
@@ -806,7 +781,7 @@ fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> hi
         })
     }
 
-    fn record_body(&mut self, value: hir::Expr, arguments: HirVec<hir::Arg>) -> hir::BodyId {
+    fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
         if self.is_generator && self.is_async_body {
             span_err!(
                 self.sess,
@@ -855,6 +830,27 @@ fn diagnostic(&self) -> &errors::Handler {
         self.sess.diagnostic()
     }
 
+    /// Reuses the span but adds information like the kind of the desugaring and features that are
+    /// allowed inside this span.
+    fn mark_span_with_reason(
+        &self,
+        reason: CompilerDesugaringKind,
+        span: Span,
+        allow_internal_unstable: Option<Lrc<[Symbol]>>,
+    ) -> Span {
+        let mark = Mark::fresh(Mark::root());
+        mark.set_expn_info(source_map::ExpnInfo {
+            call_site: span,
+            def_site: Some(span),
+            format: source_map::CompilerDesugaring(reason),
+            allow_internal_unstable,
+            allow_internal_unsafe: false,
+            local_inner_macros: false,
+            edition: edition::Edition::from_session(),
+        });
+        span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
+    }
+
     fn with_anonymous_lifetime_mode<R>(
         &mut self,
         anonymous_lifetime_mode: AnonymousLifetimeMode,
@@ -1083,6 +1079,18 @@ fn add_in_band_defs<F, T>(
             .chain(in_band_defs)
             .collect();
 
+        // FIXME(const_generics): the compiler doesn't always cope with
+        // unsorted generic parameters at the moment, so we make sure
+        // that they're ordered correctly here for now. (When we chain
+        // the `in_band_defs`, we might make the order unsorted.)
+        lowered_generics.params.sort_by_key(|param| {
+            match param.kind {
+                hir::GenericParamKind::Lifetime { .. } => ParamKindOrd::Lifetime,
+                hir::GenericParamKind::Type { .. } => ParamKindOrd::Type,
+                hir::GenericParamKind::Const { .. } => ParamKindOrd::Const,
+            }
+        });
+
         (lowered_generics, res)
     }
 
@@ -1113,27 +1121,21 @@ fn make_async_expr(
         span: Span,
         body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
     ) -> hir::ExprKind {
-        let prev_is_generator = mem::replace(&mut self.is_generator, false);
-        let prev_is_async_body = mem::replace(&mut self.is_async_body, true);
+        let capture_clause = self.lower_capture_clause(capture_clause);
         let output = match ret_ty {
             Some(ty) => FunctionRetTy::Ty(P(ty.clone())),
             None => FunctionRetTy::Default(span),
         };
-        let decl = FnDecl {
+        let ast_decl = FnDecl {
             inputs: vec![],
             output,
             c_variadic: false
         };
-        // Lower the arguments before the body otherwise the body will call `lower_res` expecting
-        // the argument to have been assigned an id already.
-        let arguments = self.lower_args(Some(&decl));
-        let body_expr = body(self);
-        let body_id = self.record_body(body_expr, arguments);
-        self.is_generator = prev_is_generator;
-        self.is_async_body = prev_is_async_body;
-
-        let capture_clause = self.lower_capture_clause(capture_clause);
-        let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, None);
+        let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
+        let body_id = self.lower_fn_body(&ast_decl, |this| {
+            this.is_async_body = true;
+            body(this)
+        });
         let generator = hir::Expr {
             hir_id: self.lower_node_id(closure_node_id),
             node: hir::ExprKind::Closure(capture_clause, decl, body_id, span,
@@ -1142,30 +1144,42 @@ fn make_async_expr(
             attrs: ThinVec::new(),
         };
 
-        let unstable_span = self.sess.source_map().mark_span_with_reason(
+        let unstable_span = self.mark_span_with_reason(
             CompilerDesugaringKind::Async,
             span,
-            Some(vec![
-                Symbol::intern("gen_future"),
-            ].into()),
+            Some(vec![sym::gen_future].into()),
         );
         let gen_future = self.expr_std_path(
             unstable_span, &[sym::future, sym::from_generator], None, ThinVec::new());
         hir::ExprKind::Call(P(gen_future), hir_vec![generator])
     }
 
-    fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
-    where
-        F: FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
-    {
-        let prev_generator = mem::replace(&mut self.is_generator, false);
-        let prev_async = mem::replace(&mut self.is_async_body, false);
-        let arguments = self.lower_args(decl);
-        let result = f(self);
-        let r = self.record_body(result, arguments);
-        self.is_generator = prev_generator;
-        self.is_async_body = prev_async;
-        return r;
+    fn lower_body(
+        &mut self,
+        f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec<hir::Arg>, hir::Expr),
+    ) -> hir::BodyId {
+        let prev_is_generator = mem::replace(&mut self.is_generator, false);
+        let prev_is_async_body = mem::replace(&mut self.is_async_body, false);
+        let (arguments, result) = f(self);
+        let body_id = self.record_body(arguments, result);
+        self.is_generator = prev_is_generator;
+        self.is_async_body = prev_is_async_body;
+        body_id
+    }
+
+    fn lower_fn_body(
+        &mut self,
+        decl: &FnDecl,
+        body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
+    ) -> hir::BodyId {
+        self.lower_body(|this| (
+            decl.inputs.iter().map(|x| this.lower_arg(x)).collect(),
+            body(this),
+        ))
+    }
+
+    fn lower_const_body(&mut self, expr: &Expr) -> hir::BodyId {
+        self.lower_body(|this| (hir_vec![], this.lower_expr(expr)))
     }
 
     fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
@@ -1314,6 +1328,7 @@ fn lower_token(&mut self, token: Token, span: Span) -> TokenStream {
 
     fn lower_arm(&mut self, arm: &Arm) -> hir::Arm {
         hir::Arm {
+            hir_id: self.next_id(),
             attrs: self.lower_attrs(&arm.attrs),
             pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
             guard: match arm.guard {
@@ -1321,6 +1336,7 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm {
                 _ => None,
             },
             body: P(self.lower_expr(&arm.body)),
+            span: arm.span,
         }
     }
 
@@ -1549,7 +1565,7 @@ fn lower_existential_impl_trait(
         // desugaring that explicitly states that we don't want to track that.
         // Not tracking it makes lints in rustc and clippy very fragile as
         // frequently opened issues show.
-        let exist_ty_span = self.sess.source_map().mark_span_with_reason(
+        let exist_ty_span = self.mark_span_with_reason(
             CompilerDesugaringKind::ExistentialReturnType,
             span,
             None,
@@ -1860,7 +1876,7 @@ fn lower_qpath(
                         index: this.def_key(def_id).parent.expect("missing parent"),
                     };
                     let type_def_id = match partial_res.base_res() {
-                        Res::Def(DefKind::AssociatedTy, def_id) if i + 2 == proj_start => {
+                        Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
                             Some(parent_def_id(self, def_id))
                         }
                         Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
@@ -1882,8 +1898,8 @@ fn lower_qpath(
                             if i + 1 == proj_start => ParenthesizedGenericArgs::Ok,
                         // `a::b::Trait(Args)::TraitItem`
                         Res::Def(DefKind::Method, _)
-                        | Res::Def(DefKind::AssociatedConst, _)
-                        | Res::Def(DefKind::AssociatedTy, _)
+                        | Res::Def(DefKind::AssocConst, _)
+                        | Res::Def(DefKind::AssocTy, _)
                             if i + 2 == proj_start =>
                         {
                             ParenthesizedGenericArgs::Ok
@@ -2254,17 +2270,10 @@ fn lower_parenthesized_parameter_data(
             init: l.init.as_ref().map(|e| P(self.lower_expr(e))),
             span: l.span,
             attrs: l.attrs.clone(),
-            source: self.lower_local_source(l.source),
+            source: hir::LocalSource::Normal,
         }, ids)
     }
 
-    fn lower_local_source(&mut self, ls: LocalSource) -> hir::LocalSource {
-        match ls {
-            LocalSource::Normal => hir::LocalSource::Normal,
-            LocalSource::AsyncFn => hir::LocalSource::AsyncFn,
-        }
-    }
-
     fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability {
         match m {
             Mutability::Mutable => hir::MutMutable,
@@ -2272,22 +2281,11 @@ fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability {
         }
     }
 
-    fn lower_args(&mut self, decl: Option<&FnDecl>) -> HirVec<hir::Arg> {
-        decl.map_or(hir_vec![], |decl| decl.inputs.iter().map(|x| self.lower_arg(x)).collect())
-    }
-
     fn lower_arg(&mut self, arg: &Arg) -> hir::Arg {
         hir::Arg {
             hir_id: self.lower_node_id(arg.id),
             pat: self.lower_pat(&arg.pat),
-            source: self.lower_arg_source(&arg.source),
-        }
-    }
-
-    fn lower_arg_source(&mut self, source: &ArgSource) -> hir::ArgSource {
-        match source {
-            ArgSource::Normal => hir::ArgSource::Normal,
-            ArgSource::AsyncFn(pat) => hir::ArgSource::AsyncFn(self.lower_pat(pat)),
+            source: hir::ArgSource::Normal,
         }
     }
 
@@ -2423,7 +2421,7 @@ fn lower_async_fn_ret_ty(
     ) -> hir::FunctionRetTy {
         let span = output.span();
 
-        let exist_ty_span = self.sess.source_map().mark_span_with_reason(
+        let exist_ty_span = self.mark_span_with_reason(
             CompilerDesugaringKind::Async,
             span,
             None,
@@ -2956,7 +2954,7 @@ fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::Stru
             ident: match f.ident {
                 Some(ident) => ident,
                 // FIXME(jseyfried): positional field hygiene
-                None => Ident::new(Symbol::intern(&index.to_string()), f.span),
+                None => Ident::new(sym::integer(index), f.span),
             },
             vis: self.lower_visibility(&f.vis, None),
             ty: self.lower_ty(&f.ty, ImplTraitContext::disallowed()),
@@ -2986,11 +2984,14 @@ fn lower_param_bounds(&mut self, bounds: &[GenericBound], mut itctx: ImplTraitCo
         bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).collect()
     }
 
-    fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
+    fn lower_block_with_stmts(
+        &mut self,
+        b: &Block,
+        targeted_by_break: bool,
+        mut stmts: Vec<hir::Stmt>,
+    ) -> P<hir::Block> {
         let mut expr = None;
 
-        let mut stmts = vec![];
-
         for (index, stmt) in b.stmts.iter().enumerate() {
             if index == b.stmts.len() - 1 {
                 if let StmtKind::Expr(ref e) = stmt.node {
@@ -3013,56 +3014,177 @@ fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
         })
     }
 
-    fn lower_async_body(
+    fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
+        self.lower_block_with_stmts(b, targeted_by_break, vec![])
+    }
+
+    fn lower_maybe_async_body(
         &mut self,
         decl: &FnDecl,
-        asyncness: &IsAsync,
+        asyncness: IsAsync,
         body: &Block,
     ) -> hir::BodyId {
-        self.lower_body(Some(&decl), |this| {
-            if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness {
-                let mut body = body.clone();
+        let closure_id = match asyncness {
+            IsAsync::Async { closure_id, .. } => closure_id,
+            IsAsync::NotAsync => return self.lower_fn_body(&decl, |this| {
+                let body = this.lower_block(body, false);
+                this.expr_block(body, ThinVec::new())
+            }),
+        };
 
-                // Async function arguments are lowered into the closure body so that they are
-                // captured and so that the drop order matches the equivalent non-async functions.
-                //
-                //     async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
-                //       async move {
-                //       }
-                //     }
-                //
-                //     // ...becomes...
-                //     fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
-                //       async move {
-                //         let __arg2 = __arg2;
-                //         let <pattern> = __arg2;
-                //         let __arg1 = __arg1;
-                //         let <pattern> = __arg1;
-                //         let __arg0 = __arg0;
-                //         let <pattern> = __arg0;
-                //       }
-                //     }
+        self.lower_body(|this| {
+            let mut arguments: Vec<hir::Arg> = Vec::new();
+            let mut statements: Vec<(hir::Stmt, Option<hir::Stmt>)> = Vec::new();
+
+            // Async function arguments are lowered into the closure body so that they are
+            // captured and so that the drop order matches the equivalent non-async functions.
+            //
+            //     async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
+            //       async move {
+            //       }
+            //     }
+            //
+            //     // ...becomes...
+            //     fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
+            //       async move {
+            //         let __arg2 = __arg2;
+            //         let <pattern> = __arg2;
+            //         let __arg1 = __arg1;
+            //         let <pattern> = __arg1;
+            //         let __arg0 = __arg0;
+            //         let <pattern> = __arg0;
+            //       }
+            //     }
+            //
+            // If `<pattern>` is a simple ident, then it is lowered to a single
+            // `let <pattern> = <pattern>;` statement as an optimization.
+            for (index, argument) in decl.inputs.iter().enumerate() {
+                let argument = this.lower_arg(argument);
+                let span = argument.pat.span;
+
+                // Check if this is a binding pattern, if so, we can optimize and avoid adding a
+                // `let <pat> = __argN;` statement. In this case, we do not rename the argument.
+                let (ident, is_simple_argument) = match argument.pat.node {
+                    hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _) =>
+                        (ident, true),
+                    _ => {
+                        // Replace the ident for bindings that aren't simple.
+                        let name = format!("__arg{}", index);
+                        let ident = Ident::from_str(&name);
+
+                        (ident, false)
+                    },
+                };
+
+                // Construct an argument representing `__argN: <ty>` to replace the argument of the
+                // async function.
                 //
-                // If `<pattern>` is a simple ident, then it is lowered to a single
-                // `let <pattern> = <pattern>;` statement as an optimization.
-                for a in arguments.iter().rev() {
-                    if let Some(pat_stmt) = a.pat_stmt.clone() {
-                        body.stmts.insert(0, pat_stmt);
+                // If this is the simple case, this argument will end up being the same as the
+                // original argument, but with a different pattern id.
+                let new_argument_id = this.next_id();
+                let desugared_span =
+                    this.mark_span_with_reason(CompilerDesugaringKind::Async, span, None);
+                let new_argument = hir::Arg {
+                    hir_id: argument.hir_id,
+                    pat: P(hir::Pat {
+                        hir_id: new_argument_id,
+                        node: hir::PatKind::Binding(hir::BindingAnnotation::Unannotated,
+                                                   new_argument_id, ident, None),
+                        span: desugared_span,
+                    }),
+                    source: hir::ArgSource::AsyncFn(argument.pat.hir_id),
+                };
+
+                let construct_stmt = |this: &mut LoweringContext<'_>, pat: P<hir::Pat>,
+                                      init_pat_id: hir::HirId| {
+                    hir::Stmt {
+                        hir_id: this.next_id(),
+                        node: hir::StmtKind::Local(P(hir::Local {
+                            pat,
+                            // We explicitly do not specify the type for any statements. When the
+                            // user's argument type is `impl Trait` then this would require the
+                            // `impl_trait_in_bindings` feature to also be present for that same
+                            // type to be valid in this binding. At the time of writing (13 Mar 19),
+                            // `impl_trait_in_bindings` is not stable.
+                            ty: None,
+                            init: Some(P(hir::Expr {
+                                span,
+                                node: hir::ExprKind::Path(hir::QPath::Resolved(None, P(hir::Path {
+                                    span,
+                                    res: Res::Local(init_pat_id),
+                                    segments: hir_vec![ hir::PathSegment::from_ident(ident) ],
+                                }))),
+                                attrs: ThinVec::new(),
+                                hir_id: this.next_id(),
+                            })),
+                            hir_id: this.next_id(),
+                            span: desugared_span,
+                            attrs: ThinVec::new(),
+                            source: hir::LocalSource::AsyncFn,
+                        })),
+                        span: desugared_span,
                     }
-                    body.stmts.insert(0, a.move_stmt.clone());
-                }
+                };
 
-                let async_expr = this.make_async_expr(
-                    CaptureBy::Value, *closure_id, None, body.span,
-                    |this| {
-                        let body = this.lower_block(&body, false);
-                        this.expr_block(body, ThinVec::new())
-                    });
-                this.expr(body.span, async_expr, ThinVec::new())
-            } else {
-                let body = this.lower_block(body, false);
-                this.expr_block(body, ThinVec::new())
+                let new_statements = if is_simple_argument {
+                    // If this is the simple case, then we only insert one statement that is
+                    // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
+                    // `HirId`s are densely assigned.
+                    (construct_stmt(this, argument.pat, new_argument_id), None)
+                } else {
+                    // If this is not the simple case, then we construct two statements:
+                    //
+                    // ```
+                    // let __argN = __argN;
+                    // let <pat> = __argN;
+                    // ```
+                    //
+                    // The first statement moves the argument into the closure and thus ensures
+                    // that the drop order is correct.
+                    //
+                    // The second statement creates the bindings that the user wrote.
+
+                    // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
+                    // because the user may have specified a `ref mut` binding in the next
+                    // statement.
+                    let hir_id = this.next_id();
+                    let move_stmt = construct_stmt(
+                        this,
+                        P(hir::Pat {
+                            hir_id,
+                            node: hir::PatKind::Binding(hir::BindingAnnotation::Mutable,
+                                                        hir_id, ident, None),
+                            span: desugared_span,
+                        }),
+                        new_argument_id,
+                    );
+
+                    // Construct the `let <pat> = __argN;` statement. We re-use the original
+                    // argument's pattern so that `HirId`s are densely assigned.
+                    let pattern_stmt = construct_stmt(this, argument.pat, hir_id);
+                    (move_stmt, Some(pattern_stmt))
+                };
+
+                arguments.push(new_argument);
+                statements.push(new_statements);
             }
+
+            let async_expr = this.make_async_expr(
+                CaptureBy::Value, closure_id, None, body.span,
+                |this| {
+                    let mut stmts = vec![];
+                    for (move_stmt, pattern_stmt) in statements.drain(..) {
+                        // Insert the `let __argN = __argN` statement first.
+                        stmts.push(move_stmt);
+                        // Then insert the `let <pat> = __argN` statement, if there is one.
+                        if let Some(pattern_stmt) = pattern_stmt {
+                            stmts.push(pattern_stmt);
+                        }
+                    }
+                    let body = this.lower_block_with_stmts(body, false, stmts);
+                    this.expr_block(body, ThinVec::new())
+                });
+            (HirVec::from(arguments), this.expr(body.span, async_expr, ThinVec::new()))
         })
     }
 
@@ -3086,7 +3208,6 @@ fn lower_item_kind(
                 self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs)
             }
             ItemKind::Static(ref t, m, ref e) => {
-                let value = self.lower_body(None, |this| this.lower_expr(e));
                 hir::ItemKind::Static(
                     self.lower_ty(
                         t,
@@ -3097,11 +3218,10 @@ fn lower_item_kind(
                         }
                     ),
                     self.lower_mutability(m),
-                    value,
+                    self.lower_const_body(e),
                 )
             }
             ItemKind::Const(ref t, ref e) => {
-                let value = self.lower_body(None, |this| this.lower_expr(e));
                 hir::ItemKind::Const(
                     self.lower_ty(
                         t,
@@ -3111,50 +3231,31 @@ fn lower_item_kind(
                             ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
                         }
                     ),
-                    value
+                    self.lower_const_body(e)
                 )
             }
-            ItemKind::Fn(ref decl, ref header, ref generics, ref body) => {
+            ItemKind::Fn(ref decl, header, ref generics, ref body) => {
                 let fn_def_id = self.resolver.definitions().local_def_id(id);
                 self.with_new_scopes(|this| {
                     this.current_item = Some(ident.span);
-                    let mut lower_fn = |decl: &FnDecl| {
-                        // Note: we don't need to change the return type from `T` to
-                        // `impl Future<Output = T>` here because lower_body
-                        // only cares about the input argument patterns in the function
-                        // declaration (decl), not the return types.
-                        let body_id = this.lower_async_body(&decl, &header.asyncness.node, body);
-
-                        let (generics, fn_decl) = this.add_in_band_defs(
-                            generics,
-                            fn_def_id,
-                            AnonymousLifetimeMode::PassThrough,
-                            |this, idty| this.lower_fn_decl(
-                                &decl,
-                                Some((fn_def_id, idty)),
-                                true,
-                                header.asyncness.node.opt_return_id()
-                            ),
-                        );
 
-                        (body_id, generics, fn_decl)
-                    };
+                    // Note: we don't need to change the return type from `T` to
+                    // `impl Future<Output = T>` here because lower_body
+                    // only cares about the input argument patterns in the function
+                    // declaration (decl), not the return types.
+                    let body_id = this.lower_maybe_async_body(&decl, header.asyncness.node, body);
 
-                    let (body_id, generics, fn_decl) = if let IsAsync::Async {
-                        arguments, ..
-                    } = &header.asyncness.node {
-                        let mut decl = decl.clone();
-                        // Replace the arguments of this async function with the generated
-                        // arguments that will be moved into the closure.
-                        for (i, a) in arguments.clone().drain(..).enumerate() {
-                            if let Some(arg) = a.arg {
-                                decl.inputs[i] = arg;
-                            }
-                        }
-                        lower_fn(&decl)
-                    } else {
-                        lower_fn(decl)
-                    };
+                    let (generics, fn_decl) = this.add_in_band_defs(
+                        generics,
+                        fn_def_id,
+                        AnonymousLifetimeMode::PassThrough,
+                        |this, idty| this.lower_fn_decl(
+                            &decl,
+                            Some((fn_def_id, idty)),
+                            true,
+                            header.asyncness.node.opt_return_id()
+                        ),
+                    );
 
                     hir::ItemKind::Fn(
                         fn_decl,
@@ -3536,7 +3637,7 @@ fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
                     self.lower_ty(ty, ImplTraitContext::disallowed()),
                     default
                         .as_ref()
-                        .map(|x| self.lower_body(None, |this| this.lower_expr(x))),
+                        .map(|x| self.lower_const_body(x)),
                 ),
             ),
             TraitItemKind::Method(ref sig, None) => {
@@ -3551,7 +3652,7 @@ fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
                 (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names)))
             }
             TraitItemKind::Method(ref sig, Some(ref body)) => {
-                let body_id = self.lower_body(Some(&sig.decl), |this| {
+                let body_id = self.lower_fn_body(&sig.decl, |this| {
                     let body = this.lower_block(body, false);
                     this.expr_block(body, ThinVec::new())
                 });
@@ -3589,13 +3690,13 @@ fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
     fn lower_trait_item_ref(&mut self, i: &TraitItem) -> hir::TraitItemRef {
         let (kind, has_default) = match i.node {
             TraitItemKind::Const(_, ref default) => {
-                (hir::AssociatedItemKind::Const, default.is_some())
+                (hir::AssocItemKind::Const, default.is_some())
             }
             TraitItemKind::Type(_, ref default) => {
-                (hir::AssociatedItemKind::Type, default.is_some())
+                (hir::AssocItemKind::Type, default.is_some())
             }
             TraitItemKind::Method(ref sig, ref default) => (
-                hir::AssociatedItemKind::Method {
+                hir::AssocItemKind::Method {
                     has_self: sig.decl.has_self(),
                 },
                 default.is_some(),
@@ -3615,48 +3716,26 @@ fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
         let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
 
         let (generics, node) = match i.node {
-            ImplItemKind::Const(ref ty, ref expr) => {
-                let body_id = self.lower_body(None, |this| this.lower_expr(expr));
-                (
-                    self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
-                    hir::ImplItemKind::Const(
-                        self.lower_ty(ty, ImplTraitContext::disallowed()),
-                        body_id,
-                    ),
-                )
-            }
+            ImplItemKind::Const(ref ty, ref expr) => (
+                self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
+                hir::ImplItemKind::Const(
+                    self.lower_ty(ty, ImplTraitContext::disallowed()),
+                    self.lower_const_body(expr),
+                ),
+            ),
             ImplItemKind::Method(ref sig, ref body) => {
-                let mut lower_method = |sig: &MethodSig| {
-                    let body_id = self.lower_async_body(
-                        &sig.decl, &sig.header.asyncness.node, body
-                    );
-                    let impl_trait_return_allow = !self.is_in_trait_impl;
-                    let (generics, sig) = self.lower_method_sig(
-                        &i.generics,
-                        sig,
-                        impl_item_def_id,
-                        impl_trait_return_allow,
-                        sig.header.asyncness.node.opt_return_id(),
-                    );
-                    (body_id, generics, sig)
-                };
-
-                let (body_id, generics, sig) = if let IsAsync::Async {
-                    ref arguments, ..
-                } = sig.header.asyncness.node {
-                    let mut sig = sig.clone();
-                    // Replace the arguments of this async function with the generated
-                    // arguments that will be moved into the closure.
-                    for (i, a) in arguments.clone().drain(..).enumerate() {
-                        if let Some(arg) = a.arg {
-                            sig.decl.inputs[i] = arg;
-                        }
-                    }
-                    lower_method(&sig)
-                } else {
-                    lower_method(sig)
-                };
                 self.current_item = Some(i.span);
+                let body_id = self.lower_maybe_async_body(
+                    &sig.decl, sig.header.asyncness.node, body
+                );
+                let impl_trait_return_allow = !self.is_in_trait_impl;
+                let (generics, sig) = self.lower_method_sig(
+                    &i.generics,
+                    sig,
+                    impl_item_def_id,
+                    impl_trait_return_allow,
+                    sig.header.asyncness.node.opt_return_id(),
+                );
 
                 (generics, hir::ImplItemKind::Method(sig, body_id))
             }
@@ -3695,10 +3774,10 @@ fn lower_impl_item_ref(&mut self, i: &ImplItem) -> hir::ImplItemRef {
             vis: self.lower_visibility(&i.vis, Some(i.id)),
             defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
             kind: match i.node {
-                ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
-                ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
-                ImplItemKind::Existential(..) => hir::AssociatedItemKind::Existential,
-                ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
+                ImplItemKind::Const(..) => hir::AssocItemKind::Const,
+                ImplItemKind::Type(..) => hir::AssocItemKind::Type,
+                ImplItemKind::Existential(..) => hir::AssocItemKind::Existential,
+                ImplItemKind::Method(ref sig, _) => hir::AssocItemKind::Method {
                     has_self: sig.decl.has_self(),
                 },
                 ImplItemKind::Macro(..) => unimplemented!(),
@@ -3848,7 +3927,7 @@ fn lower_method_sig(
         impl_trait_return_allow: bool,
         is_async: Option<NodeId>,
     ) -> (hir::Generics, hir::MethodSig) {
-        let header = self.lower_fn_header(&sig.header);
+        let header = self.lower_fn_header(sig.header);
         let (generics, decl) = self.add_in_band_defs(
             generics,
             fn_def_id,
@@ -3870,10 +3949,10 @@ fn lower_is_auto(&mut self, a: IsAuto) -> hir::IsAuto {
         }
     }
 
-    fn lower_fn_header(&mut self, h: &FnHeader) -> hir::FnHeader {
+    fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
         hir::FnHeader {
             unsafety: self.lower_unsafety(h.unsafety),
-            asyncness: self.lower_asyncness(&h.asyncness.node),
+            asyncness: self.lower_asyncness(h.asyncness.node),
             constness: self.lower_constness(h.constness),
             abi: h.abi,
         }
@@ -3893,7 +3972,7 @@ fn lower_constness(&mut self, c: Spanned<Constness>) -> hir::Constness {
         }
     }
 
-    fn lower_asyncness(&mut self, a: &IsAsync) -> hir::IsAsync {
+    fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
         match a {
             IsAsync::Async { .. } => hir::IsAsync::Async,
             IsAsync::NotAsync => hir::IsAsync::NotAsync,
@@ -4052,7 +4131,7 @@ fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
         self.with_new_scopes(|this| {
             hir::AnonConst {
                 hir_id: this.lower_node_id(c.id),
-                body: this.lower_body(None, |this| this.lower_expr(&c.value)),
+                body: this.lower_const_body(&c.value),
             }
         })
     }
@@ -4060,10 +4139,6 @@ fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
     fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
         let kind = match e.node {
             ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))),
-            ExprKind::ObsoleteInPlace(..) => {
-                self.sess.abort_if_errors();
-                span_bug!(e.span, "encountered ObsoleteInPlace expr during lowering");
-            }
             ExprKind::Array(ref exprs) => {
                 hir::ExprKind::Array(exprs.iter().map(|x| self.lower_expr(x)).collect())
             }
@@ -4143,10 +4218,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
 
                 // Lower condition:
-                let span_block = self
-                    .sess
-                    .source_map()
-                    .mark_span_with_reason(IfTemporary, cond.span, None);
+                let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
                 let cond = self.lower_expr(cond);
                 // Wrap in a construct equivalent to `{ let _t = $cond; _t }` to preserve drop
                 // semantics since `if cond { ... }` don't let temporaries live outside of `cond`.
@@ -4176,12 +4248,10 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
             }),
             ExprKind::TryBlock(ref body) => {
                 self.with_catch_scope(body.id, |this| {
-                    let unstable_span = this.sess.source_map().mark_span_with_reason(
+                    let unstable_span = this.mark_span_with_reason(
                         CompilerDesugaringKind::TryBlock,
                         body.span,
-                        Some(vec![
-                            Symbol::intern("try_trait"),
-                        ].into()),
+                        Some(vec![sym::try_trait].into()),
                     );
                     let mut block = this.lower_block(body, true).into_inner();
                     let tail = block.expr.take().map_or_else(
@@ -4216,7 +4286,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
             }
             ExprKind::Await(_origin, ref expr) => self.lower_await(e.span, expr),
             ExprKind::Closure(
-                capture_clause, ref asyncness, movability, ref decl, ref body, fn_decl_span
+                capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span
             ) => {
                 if let IsAsync::Async { closure_id, .. } = asyncness {
                     let outer_decl = FnDecl {
@@ -4249,12 +4319,12 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
 
                         // Transform `async |x: u8| -> X { ... }` into
                         // `|x: u8| future_from_generator(|| -> X { ... })`.
-                        let body_id = this.lower_body(Some(&outer_decl), |this| {
+                        let body_id = this.lower_fn_body(&outer_decl, |this| {
                             let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
                                 Some(&**ty)
                             } else { None };
                             let async_body = this.make_async_expr(
-                                capture_clause, *closure_id, async_ret_ty, body.span,
+                                capture_clause, closure_id, async_ret_ty, body.span,
                                 |this| {
                                     this.with_new_scopes(|this| this.lower_expr(body))
                                 });
@@ -4275,7 +4345,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                     self.with_new_scopes(|this| {
                         this.current_item = Some(fn_decl_span);
                         let mut is_generator = false;
-                        let body_id = this.lower_body(Some(decl), |this| {
+                        let body_id = this.lower_fn_body(decl, |this| {
                             let e = this.lower_expr(body);
                             is_generator = this.is_generator;
                             e
@@ -4610,7 +4680,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 // expand <head>
                 let mut head = self.lower_expr(head);
                 let head_sp = head.span;
-                let desugared_span = self.sess.source_map().mark_span_with_reason(
+                let desugared_span = self.mark_span_with_reason(
                     CompilerDesugaringKind::ForLoop,
                     head_sp,
                     None,
@@ -4764,13 +4834,13 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 //                 return Try::from_error(From::from(err)),
                 // }
 
-                let unstable_span = self.sess.source_map().mark_span_with_reason(
+                let unstable_span = self.mark_span_with_reason(
                     CompilerDesugaringKind::QuestionMark,
                     e.span,
                     Some(vec![sym::try_trait].into()),
                 );
                 let try_span = self.sess.source_map().end_point(e.span);
-                let try_span = self.sess.source_map().mark_span_with_reason(
+                let try_span = self.mark_span_with_reason(
                     CompilerDesugaringKind::QuestionMark,
                     try_span,
                     Some(vec![sym::try_trait].into()),
@@ -5024,9 +5094,11 @@ fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBou
 
     fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
         hir::Arm {
+            hir_id: self.next_id(),
             attrs: hir_vec![],
             pats,
             guard: None,
+            span: expr.span,
             body: expr,
         }
     }
@@ -5565,12 +5637,12 @@ fn lower_await(
             err.emit();
             return hir::ExprKind::Err;
         }
-        let span = self.sess.source_map().mark_span_with_reason(
+        let span = self.mark_span_with_reason(
             CompilerDesugaringKind::Await,
             await_span,
             None,
         );
-        let gen_future_span = self.sess.source_map().mark_span_with_reason(
+        let gen_future_span = self.mark_span_with_reason(
             CompilerDesugaringKind::Await,
             await_span,
             Some(vec![sym::gen_future].into()),