From d0c78dd7aa692a9338b2085e8d227cde73d2a5f9 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 29 May 2019 04:10:49 +0300 Subject: [PATCH 1/7] syntax: revert `ast::AsyncArgument` and associated changes. Here follows the main reverts applied in order to make this commit: Revert "Rollup merge of #60676 - davidtwco:issue-60674, r=cramertj" This reverts commit 45b09453dbf120cc23d889435aac3ed7d2ec8eb7, reversing changes made to f6df1f6c30b469cb9e65c5453a0efa03cbb6005e. Revert "Rollup merge of #60437 - davidtwco:issue-60236, r=nikomatsakis" This reverts commit 16939a50ea440e72cb6ecefdaabb988addb1ec0e, reversing changes made to 12bf98155249783583a91863c5dccf9e346f1226. Revert "Rollup merge of #59823 - davidtwco:issue-54716, r=cramertj" This reverts commit 62d1574876f5531bce1b267e62dff520d7adcbbb, reversing changes made to 4eff8526a789e0dfa8b97f7dec91b7b5c18e8544. --- src/librustc/hir/lowering.rs | 187 +++++--------------------- src/librustc/hir/map/def_collector.rs | 41 ++---- src/librustc/lint/context.rs | 24 ---- src/librustc_passes/ast_validation.rs | 6 +- src/librustc_resolve/lib.rs | 72 +++------- src/librustc_save_analysis/sig.rs | 2 +- src/libsyntax/ast.rs | 55 +------- src/libsyntax/ext/build.rs | 6 +- src/libsyntax/ext/placeholders.rs | 23 +--- src/libsyntax/mut_visit.rs | 42 +----- src/libsyntax/parse/diagnostics.rs | 2 +- src/libsyntax/parse/parser.rs | 141 ++----------------- src/libsyntax/print/pprust.rs | 23 ++-- src/libsyntax/visit.rs | 3 - src/libsyntax_ext/deriving/debug.rs | 1 - 15 files changed, 108 insertions(+), 520 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 08fbd0d20d74d..a61bdeb829915 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -465,32 +465,6 @@ impl<'a> LoweringContext<'a> { 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); @@ -2266,17 +2240,10 @@ impl<'a> LoweringContext<'a> { 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, @@ -2292,14 +2259,7 @@ impl<'a> LoweringContext<'a> { 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, } } @@ -3028,44 +2988,13 @@ impl<'a> LoweringContext<'a> { fn lower_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(); - - // 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(: , : , : ) { - // async move { - // } - // } - // - // // ...becomes... - // fn foo(__arg0: , __arg1: , __arg2: ) { - // async move { - // let __arg2 = __arg2; - // let = __arg2; - // let __arg1 = __arg1; - // let = __arg1; - // let __arg0 = __arg0; - // let = __arg0; - // } - // } - // - // If `` is a simple ident, then it is lowered to a single - // `let = ;` 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); - } - body.stmts.insert(0, a.move_stmt.clone()); - } - + if let IsAsync::Async { closure_id, .. } = asyncness { let async_expr = this.make_async_expr( - CaptureBy::Value, *closure_id, None, body.span, + CaptureBy::Value, closure_id, None, body.span, |this| { let body = this.lower_block(&body, false); this.expr_block(body, ThinVec::new()) @@ -3126,47 +3055,26 @@ impl<'a> LoweringContext<'a> { value ) } - 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| { + // Note: we don't need to change the return type from `T` to + // `impl Future` 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() + ), + ); 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` 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) - }; - - 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) - }; hir::ItemKind::Fn( fn_decl, @@ -3638,36 +3546,15 @@ impl<'a> LoweringContext<'a> { ) } 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) - }; + 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(), + ); self.current_item = Some(i.span); (generics, hir::ImplItemKind::Method(sig, body_id)) @@ -3860,7 +3747,7 @@ impl<'a> LoweringContext<'a> { impl_trait_return_allow: bool, is_async: Option, ) -> (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, @@ -3882,10 +3769,10 @@ impl<'a> LoweringContext<'a> { } } - 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, } @@ -3905,7 +3792,7 @@ impl<'a> LoweringContext<'a> { } } - 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, @@ -4222,7 +4109,7 @@ impl<'a> LoweringContext<'a> { } 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 { @@ -4260,7 +4147,7 @@ impl<'a> LoweringContext<'a> { 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)) }); diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index bde27c71f9a6d..a4484c8173898 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -64,17 +64,16 @@ impl<'a> DefCollector<'a> { id: NodeId, name: Name, span: Span, - header: &'a FnHeader, + header: &FnHeader, generics: &'a Generics, decl: &'a FnDecl, body: &'a Block, ) { - let (closure_id, return_impl_trait_id, arguments) = match &header.asyncness.node { + let (closure_id, return_impl_trait_id) = match header.asyncness.node { IsAsync::Async { closure_id, return_impl_trait_id, - arguments, - } => (closure_id, return_impl_trait_id, arguments), + } => (closure_id, return_impl_trait_id), _ => unreachable!(), }; @@ -83,38 +82,16 @@ impl<'a> DefCollector<'a> { let fn_def_data = DefPathData::ValueNs(name.as_interned_str()); let fn_def = self.create_def(id, fn_def_data, span); return self.with_parent(fn_def, |this| { - this.create_def(*return_impl_trait_id, DefPathData::ImplTrait, span); + this.create_def(return_impl_trait_id, DefPathData::ImplTrait, span); visit::walk_generics(this, generics); - - // Walk the generated arguments for the `async fn`. - for (i, a) in arguments.iter().enumerate() { - use visit::Visitor; - if let Some(arg) = &a.arg { - this.visit_ty(&arg.ty); - } else { - this.visit_ty(&decl.inputs[i].ty); - } - } - - // We do not invoke `walk_fn_decl` as this will walk the arguments that are being - // replaced. - visit::walk_fn_ret_ty(this, &decl.output); + visit::walk_fn_decl(this, decl); let closure_def = this.create_def( - *closure_id, DefPathData::ClosureExpr, span, + closure_id, DefPathData::ClosureExpr, span, ); this.with_parent(closure_def, |this| { - use visit::Visitor; - // Walk each of the generated statements before the regular block body. - for a in arguments { - this.visit_stmt(&a.move_stmt); - if let Some(pat_stmt) = &a.pat_stmt { - this.visit_stmt(&pat_stmt); - } - } - - visit::walk_block(this, &body); + visit::walk_block(this, body); }) }) } @@ -302,7 +279,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { match expr.node { ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id), - ExprKind::Closure(_, ref asyncness, ..) => { + ExprKind::Closure(_, asyncness, ..) => { let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span); @@ -311,7 +288,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // Async closures desugar to closures inside of closures, so // we must create two defs. if let IsAsync::Async { closure_id, .. } = asyncness { - let async_def = self.create_def(*closure_id, + let async_def = self.create_def(closure_id, DefPathData::ClosureExpr, expr.span); self.parent_def = Some(async_def); diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index c6583dd7a27b7..c5c6c4b944700 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1335,30 +1335,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> run_early_pass!(self, check_mac, mac); } - - fn visit_fn_header(&mut self, header: &'a ast::FnHeader) { - // Unlike in HIR lowering and name resolution, the `AsyncArgument` statements are not added - // to the function body and the arguments do not replace those in the declaration. They are - // still visited manually here so that buffered lints can be emitted. - if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node { - for a in arguments { - // Visit the argument.. - if let Some(arg) = &a.arg { - self.visit_pat(&arg.pat); - if let ast::ArgSource::AsyncFn(pat) = &arg.source { - self.visit_pat(pat); - } - self.visit_ty(&arg.ty); - } - - // ..and the statement. - self.visit_stmt(&a.move_stmt); - if let Some(pat_stmt) = &a.pat_stmt { - self.visit_stmt(&pat_stmt); - } - } - } - } } struct LateLintPassObjects<'a> { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 2afcbe8a15137..89c4a9106a477 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -222,7 +222,7 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_async(&self, span: Span, asyncness: &IsAsync) { + fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) { if asyncness.is_async() { struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`").emit() @@ -561,7 +561,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.invalid_visibility(&impl_item.vis, None); if let ImplItemKind::Method(ref sig, _) = impl_item.node { self.check_trait_fn_not_const(sig.header.constness); - self.check_trait_fn_not_async(impl_item.span, &sig.header.asyncness.node); + self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node); } } } @@ -633,7 +633,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.no_questions_in_bounds(bounds, "supertraits", true); for trait_item in trait_items { if let TraitItemKind::Method(ref sig, ref block) = trait_item.node { - self.check_trait_fn_not_async(trait_item.span, &sig.header.asyncness.node); + self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node); self.check_trait_fn_not_const(sig.header.constness); if block.is_none() { self.check_decl_no_pat(&sig.decl, |span, mut_ident| { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 21e759ccc650e..99abe69017da7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -855,15 +855,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { _: NodeId) { debug!("(resolving function) entering function"); - let (rib_kind, asyncness) = match function_kind { - FnKind::ItemFn(_, ref header, ..) => - (FnItemRibKind, &header.asyncness.node), - FnKind::Method(_, ref sig, _, _) => - (AssocItemRibKind, &sig.header.asyncness.node), - FnKind::Closure(_) => - // Async closures aren't resolved through `visit_fn`-- they're - // processed separately - (NormalRibKind, &IsAsync::NotAsync), + let rib_kind = match function_kind { + FnKind::ItemFn(..) => FnItemRibKind, + FnKind::Method(..) => AssocItemRibKind, + FnKind::Closure(_) => NormalRibKind, }; // Create a value rib for the function. @@ -874,45 +869,20 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { // Add each argument to the rib. let mut bindings_list = FxHashMap::default(); - let mut add_argument = |argument: &ast::Arg| { + for argument in &declaration.inputs { self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); + self.visit_ty(&argument.ty); - debug!("(resolving function) recorded argument"); - }; - // Walk the generated async arguments if this is an `async fn`, otherwise walk the - // normal arguments. - if let IsAsync::Async { ref arguments, .. } = asyncness { - for (i, a) in arguments.iter().enumerate() { - if let Some(arg) = &a.arg { - add_argument(&arg); - } else { - add_argument(&declaration.inputs[i]); - } - } - } else { - for a in &declaration.inputs { add_argument(a); } + debug!("(resolving function) recorded argument"); } - visit::walk_fn_ret_ty(self, &declaration.output); // Resolve the function body, potentially inside the body of an async closure match function_kind { - FnKind::ItemFn(.., body) | FnKind::Method(.., body) => { - if let IsAsync::Async { ref arguments, .. } = asyncness { - let mut body = body.clone(); - // Insert the generated statements into the body before attempting to - // resolve names. - for a in arguments.iter().rev() { - if let Some(pat_stmt) = a.pat_stmt.clone() { - body.stmts.insert(0, pat_stmt); - } - body.stmts.insert(0, a.move_stmt.clone()); - } - self.visit_block(&body); - } else { - self.visit_block(body); - } + FnKind::ItemFn(.., body) | + FnKind::Method(.., body) => { + self.visit_block(body); } FnKind::Closure(body) => { self.visit_expr(body); @@ -4178,7 +4148,7 @@ impl<'a> Resolver<'a> { let add_module_candidates = |module: Module<'_>, names: &mut Vec| { for (&(ident, _), resolution) in module.resolutions.borrow().iter() { if let Some(binding) = resolution.borrow().binding { - if !ident.is_gensymed() && filter_fn(binding.res()) { + if filter_fn(binding.res()) { names.push(TypoSuggestion { candidate: ident.name, article: binding.res().article(), @@ -4196,7 +4166,7 @@ impl<'a> Resolver<'a> { for rib in self.ribs[ns].iter().rev() { // Locals and type parameters for (ident, &res) in &rib.bindings { - if !ident.is_gensymed() && filter_fn(res) { + if filter_fn(res) { names.push(TypoSuggestion { candidate: ident.name, article: res.article(), @@ -4226,7 +4196,7 @@ impl<'a> Resolver<'a> { }, ); - if !ident.is_gensymed() && filter_fn(crate_mod) { + if filter_fn(crate_mod) { Some(TypoSuggestion { candidate: ident.name, article: "a", @@ -4249,15 +4219,13 @@ impl<'a> Resolver<'a> { // Add primitive types to the mix if filter_fn(Res::PrimTy(Bool)) { names.extend( - self.primitive_type_table.primitive_types - .iter() - .map(|(name, _)| { - TypoSuggestion { - candidate: *name, - article: "a", - kind: "primitive type", - } - }) + self.primitive_type_table.primitive_types.iter().map(|(name, _)| { + TypoSuggestion { + candidate: *name, + article: "a", + kind: "primitive type", + } + }) ) } } else { diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 109863f8a56b2..db8b5eacd94d9 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -374,7 +374,7 @@ impl Sig for ast::Item { Ok(extend_sig(ty, text, defs, vec![])) } - ast::ItemKind::Fn(ref decl, ref header, ref generics, _) => { + ast::ItemKind::Fn(ref decl, header, ref generics, _) => { let mut text = String::new(); if header.constness.node == ast::Constness::Const { text.push_str("const "); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 75e83bd9f9c74..b8a10d90c3c0a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -879,17 +879,6 @@ pub struct Local { pub id: NodeId, pub span: Span, pub attrs: ThinVec, - /// Origin of this local variable. - pub source: LocalSource, -} - -#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] -pub enum LocalSource { - /// Local was parsed from source. - Normal, - /// Within `ast::IsAsync::Async`, a local is generated that will contain the moved arguments - /// of an `async fn`. - AsyncFn, } /// An arm of a 'match'. @@ -1770,16 +1759,6 @@ pub struct Arg { pub ty: P, pub pat: P, pub id: NodeId, - pub source: ArgSource, -} - -/// The source of an argument in a function header. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub enum ArgSource { - /// Argument as written by the user. - Normal, - /// Argument from `async fn` lowering, contains the original binding pattern. - AsyncFn(P), } /// Alternative representation for `Arg`s describing `self` parameter of methods. @@ -1839,7 +1818,6 @@ impl Arg { }), ty, id: DUMMY_NODE_ID, - source: ArgSource::Normal, }; match eself.node { SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty), @@ -1894,39 +1872,18 @@ pub enum Unsafety { Normal, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct AsyncArgument { - /// `__arg0` - pub ident: Ident, - /// `__arg0: ` argument to replace existing function argument `: `. Only if - /// argument is not a simple binding. - pub arg: Option, - /// `let __arg0 = __arg0;` statement to be inserted at the start of the block. - pub move_stmt: Stmt, - /// `let = __arg0;` statement to be inserted at the start of the block, after matching - /// move statement. Only if argument is not a simple binding. - pub pat_stmt: Option, -} - -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] pub enum IsAsync { Async { closure_id: NodeId, return_impl_trait_id: NodeId, - /// This field stores the arguments and statements that are used in HIR lowering to - /// ensure that `async fn` arguments are dropped at the correct time. - /// - /// The argument and statements here are generated at parse time as they are required in - /// both the hir lowering, def collection and name resolution and this stops them needing - /// to be created in each place. - arguments: Vec, }, NotAsync, } impl IsAsync { - pub fn is_async(&self) -> bool { - if let IsAsync::Async { .. } = *self { + pub fn is_async(self) -> bool { + if let IsAsync::Async { .. } = self { true } else { false @@ -1934,12 +1891,12 @@ impl IsAsync { } /// In ths case this is an `async` return, the `NodeId` for the generated `impl Trait` item. - pub fn opt_return_id(&self) -> Option { + pub fn opt_return_id(self) -> Option { match self { IsAsync::Async { return_impl_trait_id, .. - } => Some(*return_impl_trait_id), + } => Some(return_impl_trait_id), IsAsync::NotAsync => None, } } @@ -2279,7 +2236,7 @@ impl Item { /// /// All the information between the visibility and the name of the function is /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`). -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] pub struct FnHeader { pub unsafety: Unsafety, pub asyncness: Spanned, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 9c0ffc1f6e8cb..47c79f8466a95 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -516,7 +516,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span: sp, attrs: ThinVec::new(), - source: ast::LocalSource::Normal, }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -545,7 +544,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span: sp, attrs: ThinVec::new(), - source: ast::LocalSource::Normal, }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -563,7 +561,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span, attrs: ThinVec::new(), - source: ast::LocalSource::Normal, }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -971,8 +968,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ast::Arg { ty, pat: arg_pat, - id: ast::DUMMY_NODE_ID, - source: ast::ArgSource::Normal, + id: ast::DUMMY_NODE_ID } } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 8f24d11cfd5b0..c56c156182bd6 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -101,13 +101,6 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { fn remove(&mut self, id: ast::NodeId) -> AstFragment { self.expanded_fragments.remove(&id).unwrap() } - - fn next_id(&mut self, id: &mut ast::NodeId) { - if self.monotonic { - assert_eq!(*id, ast::DUMMY_NODE_ID); - *id = self.cx.resolver.next_node_id() - } - } } impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { @@ -189,19 +182,9 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { noop_visit_block(block, self); for stmt in block.stmts.iter_mut() { - self.next_id(&mut stmt.id); - } - } - - fn visit_asyncness(&mut self, a: &mut ast::IsAsync) { - noop_visit_asyncness(a, self); - - if let ast::IsAsync::Async { ref mut arguments, .. } = a { - for argument in arguments.iter_mut() { - self.next_id(&mut argument.move_stmt.id); - if let Some(ref mut pat_stmt) = &mut argument.pat_stmt { - self.next_id(&mut pat_stmt.id); - } + if self.monotonic { + assert_eq!(stmt.id, ast::DUMMY_NODE_ID); + stmt.id = self.cx.resolver.next_node_id(); } } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 0016c0d4d7e2b..757513098995b 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -207,10 +207,6 @@ pub trait MutVisitor: Sized { noop_visit_local(l, self); } - fn visit_local_source(&mut self, l: &mut LocalSource) { - noop_visit_local_source(l, self); - } - fn visit_mac(&mut self, _mac: &mut Mac) { panic!("visit_mac disabled by default"); // N.B., see note about macros above. If you really want a visitor that @@ -234,10 +230,6 @@ pub trait MutVisitor: Sized { noop_visit_arg(a, self); } - fn visit_arg_source(&mut self, a: &mut ArgSource) { - noop_visit_arg_source(a, self); - } - fn visit_generics(&mut self, generics: &mut Generics) { noop_visit_generics(generics, self); } @@ -522,17 +514,13 @@ pub fn noop_visit_parenthesized_parameter_data(args: &mut Parenth } pub fn noop_visit_local(local: &mut P, vis: &mut T) { - let Local { id, pat, ty, init, span, attrs, source } = local.deref_mut(); + let Local { id, pat, ty, init, span, attrs } = local.deref_mut(); vis.visit_id(id); vis.visit_pat(pat); visit_opt(ty, |ty| vis.visit_ty(ty)); visit_opt(init, |init| vis.visit_expr(init)); vis.visit_span(span); visit_thin_attrs(attrs, vis); - vis.visit_local_source(source); -} - -pub fn noop_visit_local_source(_local_source: &mut LocalSource, _vis: &mut T) { } pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { @@ -571,18 +559,10 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arg(Arg { id, pat, ty, source }: &mut Arg, vis: &mut T) { +pub fn noop_visit_arg(Arg { id, pat, ty }: &mut Arg, vis: &mut T) { vis.visit_id(id); vis.visit_pat(pat); vis.visit_ty(ty); - vis.visit_arg_source(source); -} - -pub fn noop_visit_arg_source(source: &mut ArgSource, vis: &mut T) { - match source { - ArgSource::Normal => {}, - ArgSource::AsyncFn(pat) => vis.visit_pat(pat), - } } pub fn noop_visit_tt(tt: &mut TokenTree, vis: &mut T) { @@ -690,25 +670,9 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: pub fn noop_visit_asyncness(asyncness: &mut IsAsync, vis: &mut T) { match asyncness { - IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => { + IsAsync::Async { closure_id, return_impl_trait_id } => { vis.visit_id(closure_id); vis.visit_id(return_impl_trait_id); - for AsyncArgument { ident, arg, pat_stmt, move_stmt } in arguments.iter_mut() { - vis.visit_ident(ident); - if let Some(arg) = arg { - vis.visit_arg(arg); - } - visit_clobber(move_stmt, |stmt| { - vis.flat_map_stmt(stmt) - .expect_one("expected visitor to produce exactly one item") - }); - visit_opt(pat_stmt, |stmt| { - visit_clobber(stmt, |stmt| { - vis.flat_map_stmt(stmt) - .expect_one("expected visitor to produce exactly one item") - }) - }); - } } IsAsync::NotAsync => {} } diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index af9092dd5b05a..5df22f28797a4 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -27,7 +27,7 @@ crate fn dummy_arg(ident: Ident) -> Arg { span: ident.span, id: ast::DUMMY_NODE_ID }; - Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal } + Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } } pub enum Error { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f200d3ec8d5c1..d8891816c9e9c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1,9 +1,9 @@ // ignore-tidy-filelength -use crate::ast::{AngleBracketedArgs, AsyncArgument, ParenthesizedArgs, AttrStyle, BareFnTy}; +use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy}; use crate::ast::{GenericBound, TraitBoundModifier}; use crate::ast::Unsafety; -use crate::ast::{Mod, AnonConst, Arg, ArgSource, Arm, Guard, Attribute, BindingMode, TraitItemKind}; +use crate::ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind}; use crate::ast::Block; use crate::ast::{BlockCheckMode, CaptureBy, Movability}; use crate::ast::{Constness, Crate}; @@ -16,7 +16,7 @@ use crate::ast::{GenericParam, GenericParamKind}; use crate::ast::GenericArg; use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind}; use crate::ast::{Label, Lifetime}; -use crate::ast::{Local, LocalSource}; +use crate::ast::Local; use crate::ast::MacStmtStyle; use crate::ast::{Mac, Mac_, MacDelimiter}; use crate::ast::{MutTy, Mutability}; @@ -51,7 +51,7 @@ use crate::parse::diagnostics::{Error, dummy_arg}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; use rustc_target::spec::abi::{self, Abi}; -use syntax_pos::{Span, BytePos, DUMMY_SP, FileName, hygiene::CompilerDesugaringKind}; +use syntax_pos::{Span, BytePos, DUMMY_SP, FileName}; use log::debug; use std::borrow::Cow; @@ -1126,7 +1126,6 @@ impl<'a> Parser<'a> { IsAsync::Async { closure_id: ast::DUMMY_NODE_ID, return_impl_trait_id: ast::DUMMY_NODE_ID, - arguments: Vec::new(), } } else { IsAsync::NotAsync @@ -1185,12 +1184,12 @@ impl<'a> Parser<'a> { // trait item macro. (Ident::invalid(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) } else { - let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?; + let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let mut decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { + let decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... @@ -1199,7 +1198,6 @@ impl<'a> Parser<'a> { p.parse_arg_general(p.span.rust_2018(), true, false) })?; generics.where_clause = self.parse_where_clause()?; - self.construct_async_arguments(&mut asyncness, &mut decl); let sig = ast::MethodSig { header: FnHeader { @@ -1563,7 +1561,7 @@ impl<'a> Parser<'a> { } }; - Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal }) + Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) } /// Parses an argument in a lambda header (e.g., `|arg, arg|`). @@ -1581,8 +1579,7 @@ impl<'a> Parser<'a> { Ok(Arg { ty: t, pat, - id: ast::DUMMY_NODE_ID, - source: ast::ArgSource::Normal, + id: ast::DUMMY_NODE_ID }) } @@ -4213,7 +4210,6 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, span: lo.to(hi), attrs, - source: LocalSource::Normal, })) } @@ -5660,16 +5656,15 @@ impl<'a> Parser<'a> { /// Parses an item-position function declaration. fn parse_item_fn(&mut self, unsafety: Unsafety, - mut asyncness: Spanned, + asyncness: Spanned, constness: Spanned, abi: Abi) -> PResult<'a, ItemInfo> { let (ident, mut generics) = self.parse_fn_header()?; let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe; - let mut decl = self.parse_fn_decl(allow_c_variadic)?; + let decl = self.parse_fn_decl(allow_c_variadic)?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - self.construct_async_arguments(&mut asyncness, &mut decl); let header = FnHeader { unsafety, asyncness, constness, abi }; Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) } @@ -5849,14 +5844,13 @@ impl<'a> Parser<'a> { Ok((Ident::invalid(), vec![], ast::Generics::default(), ast::ImplItemKind::Macro(mac))) } else { - let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?; + let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let mut decl = self.parse_fn_decl_with_self(|p| { + let decl = self.parse_fn_decl_with_self(|p| { p.parse_arg_general(true, true, false) })?; generics.where_clause = self.parse_where_clause()?; - self.construct_async_arguments(&mut asyncness, &mut decl); *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; let header = ast::FnHeader { abi, unsafety, constness, asyncness }; @@ -7218,7 +7212,6 @@ impl<'a> Parser<'a> { respan(async_span, IsAsync::Async { closure_id: ast::DUMMY_NODE_ID, return_impl_trait_id: ast::DUMMY_NODE_ID, - arguments: Vec::new(), }), respan(fn_span, Constness::NotConst), Abi::Rust)?; @@ -7849,116 +7842,6 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ).emit(); } - - /// When lowering a `async fn` to the HIR, we need to move all of the arguments of the function - /// into the generated closure so that they are dropped when the future is polled and not when - /// it is created. - /// - /// The arguments of the function are replaced in HIR lowering with the arguments created by - /// this function and the statements created here are inserted at the top of the closure body. - fn construct_async_arguments(&mut self, asyncness: &mut Spanned, decl: &mut FnDecl) { - // FIXME(davidtwco): This function should really live in the HIR lowering but because - // the types constructed here need to be used in parts of resolve so that the correct - // locals are considered upvars, it is currently easier for it to live here in the parser, - // where it can be constructed once. - if let IsAsync::Async { ref mut arguments, .. } = asyncness.node { - for (index, input) in decl.inputs.iter_mut().enumerate() { - let id = ast::DUMMY_NODE_ID; - let span = input.pat.span; - let desugared_span = self.sess.source_map() - .mark_span_with_reason(CompilerDesugaringKind::Async, span, None); - - // Construct a name for our temporary argument. - let name = format!("__arg{}", index); - let ident = Ident::from_str(&name).gensym(); - - // Check if this is a ident pattern, if so, we can optimize and avoid adding a - // `let = __argN;` statement, instead just adding a `let = ;` - // statement. - let (binding_mode, ident, is_simple_pattern) = match input.pat.node { - PatKind::Ident(binding_mode @ BindingMode::ByValue(_), ident, _) => { - // Simple patterns like this don't have a generated argument, but they are - // moved into the closure with a statement, so any `mut` bindings on the - // argument will be unused. This binding mode can't be removed, because - // this would affect the input to procedural macros, but they can have - // their span marked as being the result of a compiler desugaring so - // that they aren't linted against. - input.pat.span = desugared_span; - - (binding_mode, ident, true) - } - _ => (BindingMode::ByValue(Mutability::Mutable), ident, false), - }; - - // Construct an argument representing `__argN: ` to replace the argument of the - // async function if it isn't a simple pattern. - let arg = if is_simple_pattern { - None - } else { - Some(Arg { - ty: input.ty.clone(), - id, - pat: P(Pat { - id, - node: PatKind::Ident( - BindingMode::ByValue(Mutability::Immutable), ident, None, - ), - span: desugared_span, - }), - source: ArgSource::AsyncFn(input.pat.clone()), - }) - }; - - // Construct a `let __argN = __argN;` statement to insert at the top of the - // async closure. This makes sure that the argument is captured by the closure and - // that the drop order is correct. - let move_local = Local { - pat: P(Pat { - id, - node: PatKind::Ident(binding_mode, ident, None), - span: desugared_span, - }), - // We explicitly do not specify the type for this statement. 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(Expr { - id, - node: ExprKind::Path(None, ast::Path { - span, - segments: vec![PathSegment { ident, id, args: None }], - }), - span, - attrs: ThinVec::new(), - })), - id, - span, - attrs: ThinVec::new(), - source: LocalSource::AsyncFn, - }; - - // Construct a `let = __argN;` statement to insert at the top of the - // async closure if this isn't a simple pattern. - let pat_stmt = if is_simple_pattern { - None - } else { - Some(Stmt { - id, - node: StmtKind::Local(P(Local { - pat: input.pat.clone(), - ..move_local.clone() - })), - span, - }) - }; - - let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span }; - arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt }); - } - } - } } pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, handler: &errors::Handler) { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index cf546332c2c9d..b81dc53ef6836 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -357,7 +357,7 @@ pub fn vis_to_string(v: &ast::Visibility) -> String { } pub fn fun_to_string(decl: &ast::FnDecl, - header: &ast::FnHeader, + header: ast::FnHeader, name: ast::Ident, generics: &ast::Generics) -> String { @@ -1040,7 +1040,7 @@ impl<'a> State<'a> { match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { self.head("")?; - self.print_fn(decl, &ast::FnHeader::default(), + self.print_fn(decl, ast::FnHeader::default(), Some(item.ident), generics, &item.vis)?; self.end()?; // end head-ibox @@ -1170,7 +1170,7 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer cbox } - ast::ItemKind::Fn(ref decl, ref header, ref param_names, ref body) => { + ast::ItemKind::Fn(ref decl, header, ref param_names, ref body) => { self.head("")?; self.print_fn( decl, @@ -1522,7 +1522,7 @@ impl<'a> State<'a> { vis: &ast::Visibility) -> io::Result<()> { self.print_fn(&m.decl, - &m.header, + m.header, Some(ident), &generics, vis) @@ -2113,7 +2113,7 @@ impl<'a> State<'a> { self.bclose_(expr.span, INDENT_UNIT)?; } ast::ExprKind::Closure( - capture_clause, ref asyncness, movability, ref decl, ref body, _) => { + capture_clause, asyncness, movability, ref decl, ref body, _) => { self.print_movability(movability)?; self.print_asyncness(asyncness)?; self.print_capture_clause(capture_clause)?; @@ -2710,7 +2710,7 @@ impl<'a> State<'a> { pub fn print_fn(&mut self, decl: &ast::FnDecl, - header: &ast::FnHeader, + header: ast::FnHeader, name: Option, generics: &ast::Generics, vis: &ast::Visibility) -> io::Result<()> { @@ -2765,7 +2765,8 @@ impl<'a> State<'a> { } } - pub fn print_asyncness(&mut self, asyncness: &ast::IsAsync) -> io::Result<()> { + pub fn print_asyncness(&mut self, asyncness: ast::IsAsync) + -> io::Result<()> { if asyncness.is_async() { self.word_nbsp("async")?; } @@ -3037,7 +3038,7 @@ impl<'a> State<'a> { span: syntax_pos::DUMMY_SP, }; self.print_fn(decl, - &ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() }, + ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() }, name, &generics, &source_map::dummy_spanned(ast::VisibilityKind::Inherited))?; @@ -3100,7 +3101,7 @@ impl<'a> State<'a> { } pub fn print_fn_header_info(&mut self, - header: &ast::FnHeader, + header: ast::FnHeader, vis: &ast::Visibility) -> io::Result<()> { self.s.word(visibility_qualified(vis, ""))?; @@ -3109,7 +3110,7 @@ impl<'a> State<'a> { ast::Constness::Const => self.word_nbsp("const")? } - self.print_asyncness(&header.asyncness.node)?; + self.print_asyncness(header.asyncness.node)?; self.print_unsafety(header.unsafety)?; if header.abi != Abi::Rust { @@ -3158,7 +3159,7 @@ mod tests { assert_eq!( fun_to_string( &decl, - &ast::FnHeader { + ast::FnHeader { unsafety: ast::Unsafety::Normal, constness: source_map::dummy_spanned(ast::Constness::NotConst), asyncness: source_map::dummy_spanned(ast::IsAsync::NotAsync), diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 4e096d68235b5..eb516b5c7c62f 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -544,9 +544,6 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FunctionR pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) { for argument in &function_declaration.inputs { visitor.visit_pat(&argument.pat); - if let ArgSource::AsyncFn(pat) = &argument.source { - visitor.visit_pat(pat); - } visitor.visit_ty(&argument.ty) } visitor.visit_fn_ret_ty(&function_declaration.output) diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index dec4c2dfc3b5e..44ddbb98809b4 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -129,7 +129,6 @@ fn stmt_let_undescore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P) -> ast id: ast::DUMMY_NODE_ID, span: sp, attrs: ThinVec::new(), - source: ast::LocalSource::Normal, }); ast::Stmt { id: ast::DUMMY_NODE_ID, From 32771071e8d6731e2ff747de04aabe9a4d499b24 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 31 May 2019 15:50:06 +0100 Subject: [PATCH 2/7] syntax/rustc: move `mark_span_with_reason` back. --- src/librustc/hir/lowering.rs | 51 +++++++++++++++++++++++++----------- src/libsyntax/source_map.rs | 21 --------------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index a61bdeb829915..df0a23c1b8671 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -50,6 +50,7 @@ use errors::Applicability; 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; @@ -58,17 +59,17 @@ use syntax::attr; 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; @@ -829,6 +830,27 @@ impl<'a> LoweringContext<'a> { 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>, + ) -> 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( &mut self, anonymous_lifetime_mode: AnonymousLifetimeMode, @@ -1128,7 +1150,7 @@ impl<'a> LoweringContext<'a> { 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![sym::gen_future].into()), @@ -1535,7 +1557,7 @@ impl<'a> LoweringContext<'a> { // 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, @@ -2395,7 +2417,7 @@ impl<'a> LoweringContext<'a> { ) -> 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, @@ -4038,10 +4060,7 @@ impl<'a> LoweringContext<'a> { 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`. @@ -4071,7 +4090,7 @@ impl<'a> LoweringContext<'a> { }), 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![sym::try_trait].into()), @@ -4503,7 +4522,7 @@ impl<'a> LoweringContext<'a> { // expand 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, @@ -4657,13 +4676,13 @@ impl<'a> LoweringContext<'a> { // 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()), @@ -5460,12 +5479,12 @@ impl<'a> LoweringContext<'a> { 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()), diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index 4b6893b242337..a21d2df416206 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -935,27 +935,6 @@ impl SourceMap { None } - - /// Reuses the span but adds information like the kind of the desugaring and features that are - /// allowed inside this span. - pub fn mark_span_with_reason( - &self, - reason: hygiene::CompilerDesugaringKind, - span: Span, - allow_internal_unstable: Option>, - ) -> Span { - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo { - call_site: span, - def_site: Some(span), - format: 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)) - } } impl SourceMapper for SourceMap { From 1e5f496143aabf1d4d158d99b73afee7b00f0650 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 29 May 2019 19:28:51 +0300 Subject: [PATCH 3/7] rustc: async fn drop order lowering in HIR 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. --- src/librustc/hir/intravisit.rs | 10 - src/librustc/hir/lowering.rs | 294 ++++++++++++++---- src/librustc/hir/map/mod.rs | 13 + src/librustc/hir/mod.rs | 14 +- .../nice_region_error/different_lifetimes.rs | 6 +- .../nice_region_error/named_anon_conflict.rs | 3 +- src/librustc/middle/resolve_lifetime.rs | 3 +- src/librustc_mir/build/mod.rs | 66 ++-- src/librustc_privacy/lib.rs | 20 -- src/librustc_typeck/check/mod.rs | 10 - src/librustc_typeck/check/writeback.rs | 10 - src/librustdoc/clean/mod.rs | 3 +- src/test/ui/async-await/issues/issue-61187.rs | 9 + .../ui/async-await/issues/issue-61187.stderr | 11 + 14 files changed, 317 insertions(+), 155 deletions(-) create mode 100644 src/test/ui/async-await/issues/issue-61187.rs create mode 100644 src/test/ui/async-await/issues/issue-61187.stderr diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 8000666044a1a..9cf365addca9b 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 df0a23c1b8671..e82b3df855035 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::BodyId { + fn record_body(&mut self, arguments: HirVec, 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(&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::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(&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 { - 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 { + fn lower_block_with_stmts( + &mut self, + b: &Block, + targeted_by_break: bool, + mut stmts: Vec, + ) -> P { 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 { + 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 = Vec::new(); + let mut statements: Vec<(hir::Stmt, Option)> = 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(: , : , : ) { + // async move { + // } + // } + // + // // ...becomes... + // fn foo(__arg0: , __arg1: , __arg2: ) { + // async move { + // let __arg2 = __arg2; + // let = __arg2; + // let __arg1 = __arg1; + // let = __arg1; + // let __arg0 = __arg0; + // let = __arg0; + // } + // } + // + // If `` is a simple ident, then it is lowered to a single + // `let = ;` 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 = __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: ` 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, + 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 = ;`. 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 = __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 = __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 = __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` 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 75799a1903174..2d3de5af9927f 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 210c0c9225a3d..817c4cb540f67 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 { - 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), + /// 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 944cc8a8b1999..46785f7ada1fe 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 2d7587b11b6f8..1eb2af2bd5818 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 593a09b6866db..f48da4762b768 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 123b46cb04820..a5d92d6c88f99 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, - Option<&'gcx hir::Pat>, - Option); +struct ArgInfo<'gcx> { + ty: Ty<'gcx>, + span: Option, + pattern: Option<&'gcx hir::Pat>, + user_pattern: Option<&'gcx hir::Pat>, + self_kind: Option, +} 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 20e18d60f076b..f084d3b9f28c3 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 82d198f0b78f7..3ada80b3e8b70 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 a535f776dfe60..6f8682e64671c 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 e68ad6a7c3b4b..319adea6b8682 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2018,8 +2018,9 @@ impl<'a> Clean 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 0000000000000..8b939b43b8bd4 --- /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) { + 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 0000000000000..a03142263202e --- /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) { + | ---- 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`. From 5e3b41e0cb7f8acef84afe3e9d464e67e7b2c891 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 2 Jun 2019 19:03:17 +0100 Subject: [PATCH 4/7] rustc: remove `HirId` from `ArgSource::AsyncFn` This commit removes the `HirId` from `ArgSource::AsyncFn`, relying on the fact that only `simple_ident` is used in each of the locations that previously took the original pattern from the `ArgSource::AsyncFn`. --- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/map/mod.rs | 13 ---- src/librustc/hir/mod.rs | 4 +- .../nice_region_error/different_lifetimes.rs | 6 +- .../nice_region_error/named_anon_conflict.rs | 3 +- src/librustc/middle/resolve_lifetime.rs | 8 +-- src/librustc_mir/build/mod.rs | 60 +++++-------------- src/librustdoc/clean/mod.rs | 3 +- .../underscore-lifetime-binders.stderr | 2 +- 9 files changed, 27 insertions(+), 74 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e82b3df855035..d6d8b60f21f27 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3092,7 +3092,7 @@ impl<'a> LoweringContext<'a> { new_argument_id, ident, None), span: desugared_span, }), - source: hir::ArgSource::AsyncFn(argument.pat.hir_id), + source: hir::ArgSource::AsyncFn, }; let construct_stmt = |this: &mut LoweringContext<'_>, pat: P, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 2d3de5af9927f..75799a1903174 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -699,19 +699,6 @@ 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 817c4cb540f67..eb338482eba91 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1937,8 +1937,8 @@ pub struct Arg { pub enum ArgSource { /// Argument as specified by the user. Normal, - /// Generated argument from `async fn` lowering, `HirId` is the original pattern. - AsyncFn(HirId), + /// Generated argument from `async fn` lowering. + AsyncFn, } /// 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 46785f7ada1fe..ecdcb4bbf114a 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,14 +86,12 @@ 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 arg_sup_pat = self.tcx().hir().original_pat_of_argument(anon_arg_sup); - let span_label_var1 = match arg_sup_pat.simple_ident() { + let span_label_var1 = match anon_arg_sup.pat.simple_ident() { Some(simple_ident) => format!(" from `{}`", simple_ident), None => String::new(), }; - let arg_sub_pat = self.tcx().hir().original_pat_of_argument(anon_arg_sub); - let span_label_var2 = match arg_sub_pat.simple_ident() { + let span_label_var2 = match anon_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 1eb2af2bd5818..0efc124e31fee 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,8 +95,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { } } - let arg_pat = self.tcx().hir().original_pat_of_argument(arg); - let (error_var, span_label_var) = match arg_pat.simple_ident() { + 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 f48da4762b768..7c57c50595bc8 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2414,10 +2414,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { have_bound_regions, } = info; - let help_name = if let Some(body) = parent { - let arg = &self.tcx.hir().body(body).arguments[index]; - let original_pat = self.tcx.hir().original_pat_of_argument(arg); - format!("`{}`", self.tcx.hir().hir_to_pretty_string(original_pat.hir_id)) + let help_name = if let Some(ident) = parent.and_then(|body| { + self.tcx.hir().body(body).arguments[index].pat.simple_ident() + }) { + format!("`{}`", ident) } else { format!("argument {}", index + 1) }; diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index a5d92d6c88f99..91106ebd77e07 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -84,23 +84,11 @@ 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 { - ty: liberated_closure_env_ty(tcx, id, body_id), - span: None, - pattern: None, - user_pattern: None, - self_kind: None, - }) + Some(ArgInfo(liberated_closure_env_ty(tcx, id, body_id), None, None, None)) } ty::Generator(..) => { let gen_ty = tcx.body_tables(body_id).node_type(id); - Some(ArgInfo { - ty: gen_ty, - span: None, - pattern: None, - user_pattern: None, - self_kind: None, - }) + Some(ArgInfo(gen_ty, None, None, None)) } _ => None, }; @@ -139,14 +127,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Body<' self_arg = None; } - 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, - } + ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&*arg.pat), self_arg) }); let arguments = implicit_argument.into_iter().chain(explicit_arguments); @@ -634,13 +615,7 @@ 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: Ty<'gcx>, - span: Option, - pattern: Option<&'gcx hir::Pat>, - user_pattern: Option<&'gcx hir::Pat>, - self_kind: Option, -} +struct ArgInfo<'gcx>(Ty<'gcx>, Option, Option<&'gcx hir::Pat>, Option); fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, fn_id: hir::HirId, @@ -901,18 +876,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { -> BlockAnd<()> { // Allocate locals for the function arguments - for &ArgInfo { ty, span: _, pattern, user_pattern, self_kind: _ } in arguments.iter() { + for &ArgInfo(ty, _, pattern, _) 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 (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, _) => - (Some(ident.name), pat.span), - _ => (None, pattern.map_or(self.fn_span, |pat| pat.span)) - } + let (name, span) = if let Some(pat) = pattern { + (pat.simple_ident().map(|ident| ident.name), pat.span) } else { (None, self.fn_span) }; @@ -937,13 +907,7 @@ 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, - span: opt_ty_info, - pattern, - user_pattern: _, - self_kind: ref self_binding - } = arg_info; + let &ArgInfo(ty, opt_ty_info, pattern, ref self_binding) = arg_info; // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop( @@ -958,7 +922,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match *pattern.kind { // Don't introduce extra copies for simple bindings - PatternKind::Binding { mutability, var, mode: BindingMode::ByValue, .. } => { + PatternKind::Binding { + mutability, + var, + mode: BindingMode::ByValue, + subpattern: None, + .. + } => { self.local_decls[local].mutability = mutability; self.local_decls[local].is_user_variable = if let Some(kind) = self_binding { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 319adea6b8682..0c00b3b20b5b3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2018,9 +2018,8 @@ impl<'a> Clean 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(original_pat), + name: name_from_pat(&body.arguments[i].pat), type_: ty.clean(cx), } }).collect() diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 654f4285f655f..ef9e7e39df0bc 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -30,7 +30,7 @@ error[E0106]: missing lifetime specifier LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } | ^^ expected lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_` or `y` + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` error: aborting due to 5 previous errors From 3ebe9ab5e7bb71e3dfc87bc556f3b0c37d4fb83a Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 2 Jun 2019 19:59:49 +0100 Subject: [PATCH 5/7] rustc: use lowering helpers This commit changes the lowering to stop creating HIR statements, expressions and patterns directly and instead uses the pre-existing helper functions. --- src/librustc/hir/lowering.rs | 83 ++++++++++++------------------------ 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d6d8b60f21f27..e9a86f708eff2 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3039,12 +3039,15 @@ impl<'a> LoweringContext<'a> { // 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. // + // from: + // // async fn foo(: , : , : ) { // async move { // } // } // - // // ...becomes... + // into: + // // fn foo(__arg0: , __arg1: , __arg2: ) { // async move { // let __arg2 = __arg2; @@ -3076,61 +3079,29 @@ impl<'a> LoweringContext<'a> { }, }; + let desugared_span = + this.mark_span_with_reason(CompilerDesugaringKind::Async, span, None); + // Construct an argument representing `__argN: ` 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_pat, new_argument_id) = this.pat_ident(desugared_span, ident); 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, - }; - - let construct_stmt = |this: &mut LoweringContext<'_>, pat: P, - 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, - } + pat: new_argument_pat, + source: hir::ArgSource::AsyncFn }; let new_statements = if is_simple_argument { // If this is the simple case, then we only insert one statement that is // `let = ;`. We re-use the original argument's pattern so that // `HirId`s are densely assigned. - (construct_stmt(this, argument.pat, new_argument_id), None) + let expr = this.expr_ident(desugared_span, ident, new_argument_id); + let stmt = this.stmt_let_pat( + desugared_span, Some(P(expr)), argument.pat, hir::LocalSource::AsyncFn); + (stmt, None) } else { // If this is not the simple case, then we construct two statements: // @@ -3147,21 +3118,19 @@ impl<'a> LoweringContext<'a> { // 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, - ); + let (move_pat, move_id) = this.pat_ident_binding_mode( + desugared_span, ident, hir::BindingAnnotation::Mutable); + let move_expr = this.expr_ident(desugared_span, ident, new_argument_id); + let move_stmt = this.stmt_let_pat( + desugared_span, Some(P(move_expr)), move_pat, hir::LocalSource::AsyncFn); // Construct the `let = __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); + let pattern_expr = this.expr_ident(desugared_span, ident, move_id); + let pattern_stmt = this.stmt_let_pat( + desugared_span, Some(P(pattern_expr)), argument.pat, + hir::LocalSource::AsyncFn); + (move_stmt, Some(pattern_stmt)) }; @@ -5251,6 +5220,10 @@ impl<'a> LoweringContext<'a> { } } + fn arg(&mut self, hir_id: hir::HirId, pat: P, source: hir::ArgSource) -> hir::Arg { + hir::Arg { hir_id, pat, source } + } + fn stmt(&mut self, span: Span, node: hir::StmtKind) -> hir::Stmt { hir::Stmt { span, node, hir_id: self.next_id() } } From 3c7e0eb5472592a8d429527858636b27efeee021 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 3 Jun 2019 10:14:27 +0100 Subject: [PATCH 6/7] rustc: construct statement vector directly This commit simplifies the previous logic to construct the statement vector directly rather than constructing a `Vec` of `(hir::Stmt, Option)` first. --- src/librustc/hir/lowering.rs | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e9a86f708eff2..ab7a854112661 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3034,7 +3034,7 @@ impl<'a> LoweringContext<'a> { self.lower_body(|this| { let mut arguments: Vec = Vec::new(); - let mut statements: Vec<(hir::Stmt, Option)> = Vec::new(); + let mut statements: Vec = 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. @@ -3094,14 +3094,14 @@ impl<'a> LoweringContext<'a> { source: hir::ArgSource::AsyncFn }; - let new_statements = if is_simple_argument { + if is_simple_argument { // If this is the simple case, then we only insert one statement that is // `let = ;`. We re-use the original argument's pattern so that // `HirId`s are densely assigned. let expr = this.expr_ident(desugared_span, ident, new_argument_id); let stmt = this.stmt_let_pat( desugared_span, Some(P(expr)), argument.pat, hir::LocalSource::AsyncFn); - (stmt, None) + statements.push(stmt); } else { // If this is not the simple case, then we construct two statements: // @@ -3131,26 +3131,17 @@ impl<'a> LoweringContext<'a> { desugared_span, Some(P(pattern_expr)), argument.pat, hir::LocalSource::AsyncFn); - (move_stmt, Some(pattern_stmt)) + statements.push(move_stmt); + statements.push(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 = __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); + let body = this.lower_block_with_stmts(body, false, statements); this.expr_block(body, ThinVec::new()) }); (HirVec::from(arguments), this.expr(body.span, async_expr, ThinVec::new())) @@ -5220,10 +5211,6 @@ impl<'a> LoweringContext<'a> { } } - fn arg(&mut self, hir_id: hir::HirId, pat: P, source: hir::ArgSource) -> hir::Arg { - hir::Arg { hir_id, pat, source } - } - fn stmt(&mut self, span: Span, node: hir::StmtKind) -> hir::Stmt { hir::Stmt { span, node, hir_id: self.next_id() } } From 2bb92aa02ff98e13970602e7a7f9555050f1dbe7 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 3 Jun 2019 11:36:19 +0100 Subject: [PATCH 7/7] rustc: remove `ArgSource` `ArgSource` is no longer used anywhere, so it can be removed. --- src/librustc/hir/lowering.rs | 2 -- src/librustc/hir/mod.rs | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ab7a854112661..14a6e93341e32 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2285,7 +2285,6 @@ impl<'a> LoweringContext<'a> { hir::Arg { hir_id: self.lower_node_id(arg.id), pat: self.lower_pat(&arg.pat), - source: hir::ArgSource::Normal, } } @@ -3091,7 +3090,6 @@ impl<'a> LoweringContext<'a> { let new_argument = hir::Arg { hir_id: argument.hir_id, pat: new_argument_pat, - source: hir::ArgSource::AsyncFn }; if is_simple_argument { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index eb338482eba91..65fc56f2c4878 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1929,16 +1929,6 @@ pub struct InlineAsm { pub struct Arg { pub pat: P, pub hir_id: HirId, - pub source: ArgSource, -} - -/// 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. - AsyncFn, } /// Represents the header (not the body) of a function declaration.