diff options
| -rw-r--r-- | src/librustc/hir/intravisit.rs | 10 | ||||
| -rw-r--r-- | src/librustc/hir/lowering.rs | 294 | ||||
| -rw-r--r-- | src/librustc/hir/map/mod.rs | 13 | ||||
| -rw-r--r-- | src/librustc/hir/mod.rs | 14 | ||||
| -rw-r--r-- | src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs | 6 | ||||
| -rw-r--r-- | src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs | 3 | ||||
| -rw-r--r-- | src/librustc/middle/resolve_lifetime.rs | 3 | ||||
| -rw-r--r-- | src/librustc_mir/build/mod.rs | 66 | ||||
| -rw-r--r-- | src/librustc_privacy/lib.rs | 20 | ||||
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 10 | ||||
| -rw-r--r-- | src/librustc_typeck/check/writeback.rs | 10 | ||||
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 3 | ||||
| -rw-r--r-- | src/test/ui/async-await/issues/issue-61187.rs | 9 | ||||
| -rw-r--r-- | src/test/ui/async-await/issues/issue-61187.stderr | 11 |
14 files changed, 317 insertions, 155 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 8000666044a..9cf365addca 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -262,9 +262,6 @@ pub trait Visitor<'v> : Sized { 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. diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index df0a23c1b86..e82b3df8550 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -781,7 +781,7 @@ impl<'a> LoweringContext<'a> { }) } - 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 @@ impl<'a> LoweringContext<'a> { 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 @@ impl<'a> LoweringContext<'a> { 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 @@ impl<'a> LoweringContext<'a> { } } - 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 @@ impl<'a> LoweringContext<'a> { 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 @@ impl<'a> LoweringContext<'a> { }) } - 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 @@ impl<'a> LoweringContext<'a> { 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 @@ impl<'a> LoweringContext<'a> { } ), 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 @@ impl<'a> LoweringContext<'a> { 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 @@ impl<'a> LoweringContext<'a> { 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 @@ impl<'a> LoweringContext<'a> { (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 @@ impl<'a> LoweringContext<'a> { 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 @@ impl<'a> LoweringContext<'a> { 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 @@ impl<'a> LoweringContext<'a> { 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 @@ impl<'a> LoweringContext<'a> { // 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 @@ impl<'a> LoweringContext<'a> { 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 diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 75799a19031..2d3de5af992 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -699,6 +699,19 @@ impl<'hir> Map<'hir> { } } + /// 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, diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 210c0c9225a..817c4cb540f 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -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. diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs index 944cc8a8b19..46785f7ada1 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -86,12 +86,14 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { 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(), }; diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 2d7587b11b6..1eb2af2bd58 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -95,7 +95,8 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { } } - 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), diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 593a09b6866..f48da4762b7 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2416,7 +2416,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { 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) }; diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 123b46cb048..a5d92d6c88f 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -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 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { -> 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 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // 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( diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 20e18d60f07..f084d3b9f28 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -948,16 +948,6 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { 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) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 82d198f0b78..3ada80b3e8b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1009,16 +1009,6 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { // 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 diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index a535f776dfe..6f8682e6467 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -311,16 +311,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { 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> { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e68ad6a7c3b..319adea6b86 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2018,8 +2018,9 @@ impl<'a> Clean<Arguments> for (&'a [hir::Ty], hir::BodyId) { 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 index 00000000000..8b939b43b8b --- /dev/null +++ b/src/test/ui/async-await/issues/issue-61187.rs @@ -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 index 00000000000..a0314226320 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-61187.stderr @@ -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`. |
