]> git.lizzy.rs Git - rust.git/commitdiff
rustc: async fn drop order lowering in HIR
authorDavid Wood <david@davidtw.co>
Wed, 29 May 2019 16:28:51 +0000 (19:28 +0300)
committerDavid Wood <david@davidtw.co>
Mon, 3 Jun 2019 09:20:35 +0000 (10:20 +0100)
This commit re-implements the async fn drop order lowering changes so
that it all takes place in HIR lowering, building atop the work done by
`@eddyb` to refactor `Res::Upvar`.

Previously, this types involved in the lowering were constructed in
libsyntax as they had to be used during name resolution and HIR
lowering. This was awful because none of that logic should have existed
in libsyntax.

This commit also changes `ArgSource` to keep a `HirId` to the original
argument pattern rather than a cloned copy of the pattern.

14 files changed:
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs
src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc_mir/build/mod.rs
src/librustc_privacy/lib.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/writeback.rs
src/librustdoc/clean/mod.rs
src/test/ui/async-await/issues/issue-61187.rs [new file with mode: 0644]
src/test/ui/async-await/issues/issue-61187.stderr [new file with mode: 0644]

index 8000666044a1aeddeee0dcb9135456365d19cd17..9cf365addca9bb060e3a5c941d1c38d0c3230fd9 100644 (file)
@@ -262,9 +262,6 @@ fn visit_arm(&mut self, a: &'v Arm) {
     fn visit_pat(&mut self, p: &'v Pat) {
         walk_pat(self, p)
     }
-    fn visit_argument_source(&mut self, s: &'v ArgSource) {
-        walk_argument_source(self, s)
-    }
     fn visit_anon_const(&mut self, c: &'v AnonConst) {
         walk_anon_const(self, c)
     }
@@ -402,17 +399,10 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
     for argument in &body.arguments {
         visitor.visit_id(argument.hir_id);
         visitor.visit_pat(&argument.pat);
-        visitor.visit_argument_source(&argument.source);
     }
     visitor.visit_expr(&body.value);
 }
 
-pub fn walk_argument_source<'v, V: Visitor<'v>>(visitor: &mut V, source: &'v ArgSource) {
-    if let ArgSource::AsyncFn(pat) = source {
-        visitor.visit_pat(pat);
-    }
-}
-
 pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
     // Intentionally visiting the expr first - the initialization expr
     // dominates the local's definition.
index df0a23c1b867109044ee3800e08809a14f7a2244..e82b3df8550357139f7e6f6607ed4f878a50f986 100644 (file)
@@ -781,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,
@@ -1121,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,
@@ -1160,18 +1154,32 @@ fn make_async_expr(
         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
@@ -2273,10 +2281,6 @@ 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),
@@ -2980,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 {
@@ -3007,25 +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,
         body: &Block,
     ) -> hir::BodyId {
-        self.lower_body(Some(&decl), |this| {
-            if let IsAsync::Async { closure_id, .. } = asyncness {
-                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 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())
+            }),
+        };
+
+        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 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,
+                    }
+                };
+
+                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()))
         })
     }
 
@@ -3049,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,
@@ -3060,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,
@@ -3074,29 +3231,31 @@ fn lower_item_kind(
                             ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
                         }
                     ),
-                    value
+                    self.lower_const_body(e)
                 )
             }
             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);
+
                     // 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 body_id = this.lower_maybe_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,
+                            &decl,
                             Some((fn_def_id, idty)),
                             true,
                             header.asyncness.node.opt_return_id()
                         ),
                     );
-                    this.current_item = Some(ident.span);
 
                     hir::ItemKind::Fn(
                         fn_decl,
@@ -3478,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) => {
@@ -3493,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())
                 });
@@ -3557,18 +3716,18 @@ 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 body_id = self.lower_async_body(&sig.decl, sig.header.asyncness.node, body);
+                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,
@@ -3577,7 +3736,6 @@ fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
                     impl_trait_return_allow,
                     sig.header.asyncness.node.opt_return_id(),
                 );
-                self.current_item = Some(i.span);
 
                 (generics, hir::ImplItemKind::Method(sig, body_id))
             }
@@ -3973,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),
             }
         })
     }
@@ -4161,7 +4319,7 @@ 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 };
@@ -4187,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
index 75799a1903174270912f5babb8616412a8f7710f..2d3de5af9927fe76786ce01b712be051a5135771 100644 (file)
@@ -699,6 +699,19 @@ pub fn is_argument(&self, id: NodeId) -> bool {
         }
     }
 
+    /// Returns the `HirId` of this pattern, or, if this is an `async fn` desugaring, the `HirId`
+    /// of the original pattern that the user wrote.
+    pub fn original_pat_of_argument(&self, arg: &'hir Arg) -> &'hir Pat {
+        match &arg.source {
+            ArgSource::Normal => &*arg.pat,
+            ArgSource::AsyncFn(hir_id) => match self.find_by_hir_id(*hir_id) {
+                Some(Node::Pat(pat)) | Some(Node::Binding(pat)) => &pat,
+                Some(Node::Local(local)) => &*local.pat,
+                x => bug!("ArgSource::AsyncFn HirId not a pattern/binding/local: {:?}", x),
+            },
+        }
+    }
+
     pub fn is_const_scope(&self, hir_id: HirId) -> bool {
         self.walk_parent_nodes(hir_id, |node| match *node {
             Node::Item(Item { node: ItemKind::Const(_, _), .. }) => true,
index 210c0c9225a3d9bb3afb74564c59d21b11595e6f..817c4cb540f67f20ff13425876eace1e3b9fc308 100644 (file)
@@ -1932,23 +1932,13 @@ pub struct Arg {
     pub source: ArgSource,
 }
 
-impl Arg {
-    /// Returns the pattern representing the original binding for this argument.
-    pub fn original_pat(&self) -> &P<Pat> {
-        match &self.source {
-            ArgSource::Normal => &self.pat,
-            ArgSource::AsyncFn(pat) => &pat,
-        }
-    }
-}
-
 /// Represents the source of an argument in a function header.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum ArgSource {
     /// Argument as specified by the user.
     Normal,
-    /// Generated argument from `async fn` lowering, contains the original binding pattern.
-    AsyncFn(P<Pat>),
+    /// Generated argument from `async fn` lowering, `HirId` is the original pattern.
+    AsyncFn(HirId),
 }
 
 /// Represents the header (not the body) of a function declaration.
index 944cc8a8b1999b0112ca47b95ea4ede49cb825fc..46785f7ada1feecd691074f3708c68f8abdb1c20 100644 (file)
@@ -86,12 +86,14 @@ pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
         let sub_is_ret_type =
             self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
 
-        let span_label_var1 = match anon_arg_sup.original_pat().simple_ident() {
+        let arg_sup_pat = self.tcx().hir().original_pat_of_argument(anon_arg_sup);
+        let span_label_var1 = match arg_sup_pat.simple_ident() {
             Some(simple_ident) => format!(" from `{}`", simple_ident),
             None => String::new(),
         };
 
-        let span_label_var2 = match anon_arg_sub.original_pat().simple_ident() {
+        let arg_sub_pat = self.tcx().hir().original_pat_of_argument(anon_arg_sub);
+        let span_label_var2 = match arg_sub_pat.simple_ident() {
             Some(simple_ident) => format!(" into `{}`", simple_ident),
             None => String::new(),
         };
index 2d7587b11b6f8e51ea905ddc5c3f0cedfcf9fd2d..1eb2af2bd58180ec41e582b1999e5842ca278291 100644 (file)
@@ -95,7 +95,8 @@ pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<
             }
         }
 
-        let (error_var, span_label_var) = match arg.original_pat().simple_ident() {
+        let arg_pat = self.tcx().hir().original_pat_of_argument(arg);
+        let (error_var, span_label_var) = match arg_pat.simple_ident() {
             Some(simple_ident) => (
                 format!("the type of `{}`", simple_ident),
                 format!("the type of `{}`", simple_ident),
index 593a09b6866dbb8335b58c42b5be149941b1bf64..f48da4762b768022c34acc4a1b0c51bdf73f2784 100644 (file)
@@ -2416,7 +2416,8 @@ fn report_elision_failure(
 
             let help_name = if let Some(body) = parent {
                 let arg = &self.tcx.hir().body(body).arguments[index];
-                format!("`{}`", self.tcx.hir().hir_to_pretty_string(arg.original_pat().hir_id))
+                let original_pat = self.tcx.hir().original_pat_of_argument(arg);
+                format!("`{}`", self.tcx.hir().hir_to_pretty_string(original_pat.hir_id))
             } else {
                 format!("argument {}", index + 1)
             };
index 123b46cb04820dec34d5b106896f6eaab4ac0c7a..a5d92d6c88f9923fd5d9e8af63f28c8950fff024 100644 (file)
@@ -84,11 +84,23 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Body<'
                     // HACK(eddyb) Avoid having RustCall on closures,
                     // as it adds unnecessary (and wrong) auto-tupling.
                     abi = Abi::Rust;
-                    Some(ArgInfo(liberated_closure_env_ty(tcx, id, body_id), None, None, None))
+                    Some(ArgInfo {
+                        ty: liberated_closure_env_ty(tcx, id, body_id),
+                        span: None,
+                        pattern: None,
+                        user_pattern: None,
+                        self_kind: None,
+                    })
                 }
                 ty::Generator(..) => {
                     let gen_ty = tcx.body_tables(body_id).node_type(id);
-                    Some(ArgInfo(gen_ty, None, None, None))
+                    Some(ArgInfo {
+                        ty: gen_ty,
+                        span: None,
+                        pattern: None,
+                        user_pattern: None,
+                        self_kind: None,
+                    })
                 }
                 _ => None,
             };
@@ -126,7 +138,15 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Body<'
                             opt_ty_info = None;
                             self_arg = None;
                         }
-                        ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&*arg.pat), self_arg)
+
+                        let original_pat = tcx.hir().original_pat_of_argument(arg);
+                        ArgInfo {
+                            ty: fn_sig.inputs()[index],
+                            span: opt_ty_info,
+                            pattern: Some(&*arg.pat),
+                            user_pattern: Some(&original_pat),
+                            self_kind: self_arg,
+                        }
                     });
 
             let arguments = implicit_argument.into_iter().chain(explicit_arguments);
@@ -614,10 +634,13 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 ///////////////////////////////////////////////////////////////////////////
 /// the main entry point for building MIR for a function
 
-struct ArgInfo<'gcx>(Ty<'gcx>,
-                     Option<Span>,
-                     Option<&'gcx hir::Pat>,
-                     Option<ImplicitSelfKind>);
+struct ArgInfo<'gcx> {
+    ty: Ty<'gcx>,
+    span: Option<Span>,
+    pattern: Option<&'gcx hir::Pat>,
+    user_pattern: Option<&'gcx hir::Pat>,
+    self_kind: Option<ImplicitSelfKind>,
+}
 
 fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                                    fn_id: hir::HirId,
@@ -878,26 +901,23 @@ fn args_and_body(&mut self,
                      -> BlockAnd<()>
     {
         // Allocate locals for the function arguments
-        for &ArgInfo(ty, _, pattern, _) in arguments.iter() {
+        for &ArgInfo { ty, span: _, pattern, user_pattern, self_kind: _ } in arguments.iter() {
             // If this is a simple binding pattern, give the local a name for
             // debuginfo and so that error reporting knows that this is a user
             // variable. For any other pattern the pattern introduces new
             // variables which will be named instead.
-            let mut name = None;
-            if let Some(pat) = pattern {
+            let (name, span) = if let Some(pat) = user_pattern {
                 match pat.node {
                     hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _)
-                    | hir::PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, _) => {
-                        name = Some(ident.name);
-                    }
-                    _ => (),
+                    | hir::PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, _) =>
+                        (Some(ident.name), pat.span),
+                    _ => (None, pattern.map_or(self.fn_span, |pat| pat.span))
                 }
-            }
-
-            let source_info = SourceInfo {
-                scope: OUTERMOST_SOURCE_SCOPE,
-                span: pattern.map_or(self.fn_span, |pat| pat.span)
+            } else {
+                (None, self.fn_span)
             };
+
+            let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span, };
             self.local_decls.push(LocalDecl {
                 mutability: Mutability::Mut,
                 ty,
@@ -917,7 +937,13 @@ fn args_and_body(&mut self,
             // Function arguments always get the first Local indices after the return place
             let local = Local::new(index + 1);
             let place = Place::Base(PlaceBase::Local(local));
-            let &ArgInfo(ty, opt_ty_info, pattern, ref self_binding) = arg_info;
+            let &ArgInfo {
+                ty,
+                span: opt_ty_info,
+                pattern,
+                user_pattern: _,
+                self_kind: ref self_binding
+            } = arg_info;
 
             // Make sure we drop (parts of) the argument even when not matched on.
             self.schedule_drop(
index 20e18d60f076b43e36fbb762c0f281eac43c096b..f084d3b9f28c3a4c8c7dae9793f215a4fd24cf58 100644 (file)
@@ -948,16 +948,6 @@ fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
 
         intravisit::walk_pat(self, pat);
     }
-
-    fn visit_argument_source(&mut self, s: &'tcx hir::ArgSource) {
-        match s {
-            // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
-            // a `NodeId` w/out a type, as it is only used for getting the name of the original
-            // pattern for diagnostics where only an `hir::Arg` is present.
-            hir::ArgSource::AsyncFn(..) => {},
-            _ => intravisit::walk_argument_source(self, s),
-        }
-    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////
@@ -1147,16 +1137,6 @@ fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
         intravisit::walk_pat(self, pattern);
     }
 
-    fn visit_argument_source(&mut self, s: &'tcx hir::ArgSource) {
-        match s {
-            // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
-            // a `NodeId` w/out a type, as it is only used for getting the name of the original
-            // pattern for diagnostics where only an `hir::Arg` is present.
-            hir::ArgSource::AsyncFn(..) => {},
-            _ => intravisit::walk_argument_source(self, s),
-        }
-    }
-
     fn visit_local(&mut self, local: &'tcx hir::Local) {
         if let Some(ref init) = local.init {
             if self.check_expr_pat_type(init.hir_id, init.span) {
index 82d198f0b78f78cc7c0b91b357456b563a3d8c1d..3ada80b3e8b7015e03df59364917ae815ec77cbd 100644 (file)
@@ -1009,16 +1009,6 @@ fn visit_pat(&mut self, p: &'gcx hir::Pat) {
     // Don't descend into the bodies of nested closures
     fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
                 _: hir::BodyId, _: Span, _: hir::HirId) { }
-
-    fn visit_argument_source(&mut self, s: &'gcx hir::ArgSource) {
-        match s {
-            // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
-            // a `NodeId` w/out a type, as it is only used for getting the name of the original
-            // pattern for diagnostics where only an `hir::Arg` is present.
-            hir::ArgSource::AsyncFn(..) => {},
-            _ => intravisit::walk_argument_source(self, s),
-        }
-    }
 }
 
 /// When `check_fn` is invoked on a generator (i.e., a body that
index a535f776dfe602c336e9b7a3b85792a637821795..6f8682e64671c3fb4afe381816858d7c0f7c907d 100644 (file)
@@ -311,16 +311,6 @@ fn visit_ty(&mut self, hir_ty: &'gcx hir::Ty) {
         let ty = self.resolve(&ty, &hir_ty.span);
         self.write_ty_to_tables(hir_ty.hir_id, ty);
     }
-
-    fn visit_argument_source(&mut self, s: &'gcx hir::ArgSource) {
-        match s {
-            // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
-            // a `NodeId` w/out a type, as it is only used for getting the name of the original
-            // pattern for diagnostics where only an `hir::Arg` is present.
-            hir::ArgSource::AsyncFn(..) => {},
-            _ => intravisit::walk_argument_source(self, s),
-        }
-    }
 }
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
index e68ad6a7c3b4bc375c6e5a8f7db6c0298cd67aaa..319adea6b86820da580e72a0309052b5967f6d9d 100644 (file)
@@ -2018,8 +2018,9 @@ fn clean(&self, cx: &DocContext<'_>) -> Arguments {
 
         Arguments {
             values: self.0.iter().enumerate().map(|(i, ty)| {
+                let original_pat = cx.tcx.hir().original_pat_of_argument(&body.arguments[i]);
                 Argument {
-                    name: name_from_pat(&body.arguments[i].original_pat()),
+                    name: name_from_pat(original_pat),
                     type_: ty.clean(cx),
                 }
             }).collect()
diff --git a/src/test/ui/async-await/issues/issue-61187.rs b/src/test/ui/async-await/issues/issue-61187.rs
new file mode 100644 (file)
index 0000000..8b939b4
--- /dev/null
@@ -0,0 +1,9 @@
+// edition:2018
+#![feature(async_await)]
+
+fn main() {
+}
+
+async fn response(data: Vec<u8>) {
+    data.reverse(); //~ ERROR E0596
+}
diff --git a/src/test/ui/async-await/issues/issue-61187.stderr b/src/test/ui/async-await/issues/issue-61187.stderr
new file mode 100644 (file)
index 0000000..a031422
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable
+  --> $DIR/issue-61187.rs:8:5
+   |
+LL | async fn response(data: Vec<u8>) {
+   |                   ---- help: consider changing this to be mutable: `mut data`
+LL |     data.reverse();
+   |     ^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.