]> git.lizzy.rs Git - rust.git/commitdiff
Async methods
authorTaylor Cramer <cramertj@google.com>
Tue, 19 Jun 2018 04:18:10 +0000 (21:18 -0700)
committerTaylor Cramer <cramertj@google.com>
Fri, 22 Jun 2018 05:38:05 +0000 (22:38 -0700)
src/librustc/hir/lowering.rs
src/librustc/hir/map/def_collector.rs
src/librustc_passes/ast_validation.rs
src/librustc_passes/diagnostics.rs
src/librustc_resolve/lib.rs
src/libsyntax/parse/parser.rs
src/test/run-pass/async-await.rs
src/test/ui/async-fn-multiple-lifetimes.stderr

index 2deb0b53e6bb5d37f58afb35b6719b40e3084896..e694dc64ab3ce9e5d65901cc6d41e7cbd8001eac 100644 (file)
@@ -2932,7 +2932,7 @@ fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
                     AnonymousLifetimeMode::PassThrough,
                     |this| {
                         hir::TraitItemKind::Method(
-                            this.lower_method_sig(sig, trait_item_def_id, false),
+                            this.lower_method_sig(sig, trait_item_def_id, false, false),
                             hir::TraitMethod::Required(names),
                         )
                     },
@@ -2950,7 +2950,7 @@ fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
                     AnonymousLifetimeMode::PassThrough,
                     |this| {
                         hir::TraitItemKind::Method(
-                            this.lower_method_sig(sig, trait_item_def_id, false),
+                            this.lower_method_sig(sig, trait_item_def_id, false, false),
                             hir::TraitMethod::Provided(body_id),
                         )
                     },
@@ -3021,8 +3021,18 @@ fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
             }
             ImplItemKind::Method(ref sig, ref body) => {
                 let body_id = self.lower_body(Some(&sig.decl), |this| {
-                    let body = this.lower_block(body, false);
-                    this.expr_block(body, ThinVec::new())
+                    if let IsAsync::Async(async_node_id) = sig.header.asyncness {
+                        let async_expr = this.make_async_expr(
+                            CaptureBy::Value, async_node_id, None,
+                            |this| {
+                                let body = this.lower_block(body, false);
+                                this.expr_block(body, ThinVec::new())
+                            });
+                        this.expr(body.span, async_expr, ThinVec::new())
+                    } else {
+                        let body = this.lower_block(body, false);
+                        this.expr_block(body, ThinVec::new())
+                    }
                 });
                 let impl_trait_return_allow = !self.is_in_trait_impl;
 
@@ -3036,6 +3046,7 @@ fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
                                 sig,
                                 impl_item_def_id,
                                 impl_trait_return_allow,
+                                sig.header.asyncness.is_async(),
                             ),
                             body_id,
                         )
@@ -3201,10 +3212,11 @@ fn lower_method_sig(
         sig: &MethodSig,
         fn_def_id: DefId,
         impl_trait_return_allow: bool,
+        is_async: bool,
     ) -> hir::MethodSig {
         hir::MethodSig {
             header: self.lower_fn_header(sig.header),
-            decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, false),
+            decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, is_async),
         }
     }
 
index 335e38bbe7e220b7cdee577594ed4f0e26b92762..7c71401c8b2e8cbc6f54a734a70322ddcf9f303d 100644 (file)
@@ -73,6 +73,27 @@ pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F)
         self.parent_def = parent;
     }
 
+    fn visit_async_fn(
+        &mut self,
+        id: NodeId,
+        async_node_id: NodeId,
+        name: Name,
+        span: Span,
+        visit_fn: impl FnOnce(&mut DefCollector<'a>)
+    ) {
+        // For async functions, we need to create their inner defs inside of a
+        // closure to match their desugared representation.
+        let fn_def_data = DefPathData::ValueNs(name.as_interned_str());
+        let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span);
+        return self.with_parent(fn_def, |this| {
+            let closure_def = this.create_def(async_node_id,
+                                  DefPathData::ClosureExpr,
+                                  REGULAR_SPACE,
+                                  span);
+            this.with_parent(closure_def, visit_fn)
+        })
+    }
+
     fn visit_macro_invoc(&mut self, id: NodeId) {
         if let Some(ref mut visit) = self.visit_macro_invoc {
             visit(MacroInvocationData {
@@ -100,19 +121,13 @@ fn visit_item(&mut self, i: &'a Item) {
                 return visit::walk_item(self, i);
             }
             ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..) => {
-                // For async functions, we need to create their inner defs inside of a
-                // closure to match their desugared representation.
-                let fn_def_data = DefPathData::ValueNs(i.ident.name.as_interned_str());
-                let fn_def = self.create_def(i.id, fn_def_data, ITEM_LIKE_SPACE, i.span);
-                return self.with_parent(fn_def, |this| {
-                    let closure_def = this.create_def(async_node_id,
-                                          DefPathData::ClosureExpr,
-                                          REGULAR_SPACE,
-                                          i.span);
-                    this.with_parent(closure_def, |this| {
-                        visit::walk_item(this, i);
-                    })
-                });
+                return self.visit_async_fn(
+                    i.id,
+                    async_node_id,
+                    i.ident.name,
+                    i.span,
+                    |this| visit::walk_item(this, i)
+                )
             }
             ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_interned_str()),
             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
@@ -212,6 +227,17 @@ fn visit_trait_item(&mut self, ti: &'a TraitItem) {
 
     fn visit_impl_item(&mut self, ii: &'a ImplItem) {
         let def_data = match ii.node {
+            ImplItemKind::Method(MethodSig {
+                header: FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..
+            }, ..) => {
+                return self.visit_async_fn(
+                    ii.id,
+                    async_node_id,
+                    ii.ident.name,
+                    ii.span,
+                    |this| visit::walk_impl_item(this, ii)
+                )
+            }
             ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
                 DefPathData::ValueNs(ii.ident.name.as_interned_str()),
             ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_interned_str()),
index 8111caed5c59aaf9f5bab450bdcbf73721141c58..7cdcdf4f0d109ccd579585b1182acb7b6492503a 100644 (file)
@@ -87,6 +87,13 @@ fn check_decl_no_pat<ReportFn: Fn(Span, bool)>(&self, decl: &FnDecl, report_err:
         }
     }
 
+    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()
+        }
+    }
+
     fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
         match constness.node {
             Constness::Const => {
@@ -309,6 +316,7 @@ fn visit_item(&mut self, item: &'a Item) {
                 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);
                         self.check_trait_fn_not_const(sig.header.constness);
                         if block.is_none() {
                             self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
index d031694d85308a1d1cbc97f9aaec3f21a2540acf..f1ec3371c3b9ab0400bd0b3a60daecff1497dcd3 100644 (file)
@@ -310,4 +310,5 @@ fn foo() {}
     E0666, // nested `impl Trait` is illegal
     E0667, // `impl Trait` in projections
     E0696, // `continue` pointing to a labeled block
+    E0706, // `async fn` in trait
 }
index d3c1929159414a8f19e73ee38458954926c22d30..26e6e80ce1861bd6b49a2d8eeb45d15cd8abdbb7 100644 (file)
@@ -746,15 +746,17 @@ fn visit_fn(&mut self,
                 function_kind: FnKind<'tcx>,
                 declaration: &'tcx FnDecl,
                 _: Span,
-                node_id: NodeId) {
-        let rib_kind = match function_kind {
-            FnKind::ItemFn(..) => {
-                ItemRibKind
-            }
-            FnKind::Method(_, _, _, _) => {
-                TraitOrImplItemRibKind
-            }
-            FnKind::Closure(_) => ClosureRibKind(node_id),
+                node_id: NodeId)
+    {
+        let (rib_kind, asyncness) = match function_kind {
+            FnKind::ItemFn(_, ref header, ..) =>
+                (ItemRibKind, header.asyncness),
+            FnKind::Method(_, ref sig, _, _) =>
+                (TraitOrImplItemRibKind, sig.header.asyncness),
+            FnKind::Closure(_) =>
+                // Async closures aren't resolved through `visit_fn`-- they're
+                // processed separately
+                (ClosureRibKind(node_id), IsAsync::NotAsync),
         };
 
         // Create a value rib for the function.
@@ -774,7 +776,13 @@ fn visit_fn(&mut self,
         }
         visit::walk_fn_ret_ty(self, &declaration.output);
 
-        // Resolve the function body.
+        // Resolve the function body, potentially inside the body of an async closure
+        if let IsAsync::Async(async_closure_id) = asyncness {
+            let rib_kind = ClosureRibKind(async_closure_id);
+            self.ribs[ValueNS].push(Rib::new(rib_kind));
+            self.label_ribs.push(Rib::new(rib_kind));
+        }
+
         match function_kind {
             FnKind::ItemFn(.., body) |
             FnKind::Method(.., body) => {
@@ -785,6 +793,12 @@ fn visit_fn(&mut self,
             }
         };
 
+        // Leave the body of the async closure
+        if asyncness.is_async() {
+            self.label_ribs.pop();
+            self.ribs[ValueNS].pop();
+        }
+
         debug!("(resolving function) leaving function");
 
         self.label_ribs.pop();
@@ -2054,47 +2068,6 @@ fn resolve_item(&mut self, item: &Item) {
         self.check_proc_macro_attrs(&item.attrs);
 
         match item.node {
-            ItemKind::Fn(ref declaration,
-                         FnHeader { asyncness: IsAsync::Async(async_closure_id), .. },
-                         ref generics,
-                         ref body) => {
-                // Async functions are desugared from `async fn foo() { .. }`
-                // to `fn foo() { future_from_generator(move || ... ) }`,
-                // so we have to visit the body inside the closure scope
-                self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
-                    this.visit_vis(&item.vis);
-                    this.visit_ident(item.ident);
-                    this.visit_generics(generics);
-                    let rib_kind = ItemRibKind;
-                    this.ribs[ValueNS].push(Rib::new(rib_kind));
-                    this.label_ribs.push(Rib::new(rib_kind));
-                    let mut bindings_list = FxHashMap();
-                    for argument in &declaration.inputs {
-                        this.resolve_pattern(
-                            &argument.pat, PatternSource::FnParam, &mut bindings_list);
-                        this.visit_ty(&*argument.ty);
-                    }
-                    visit::walk_fn_ret_ty(this, &declaration.output);
-
-                    // Now resolve the inner closure
-                    {
-                        let rib_kind = ClosureRibKind(async_closure_id);
-                        this.ribs[ValueNS].push(Rib::new(rib_kind));
-                        this.label_ribs.push(Rib::new(rib_kind));
-                        // No need to resolve either arguments nor return type,
-                        // as this closure has neither
-
-                        // Resolve the body
-                        this.visit_block(body);
-                        this.label_ribs.pop();
-                        this.ribs[ValueNS].pop();
-                    }
-                    this.label_ribs.pop();
-                    this.ribs[ValueNS].pop();
-
-                    walk_list!(this, visit_attribute, &item.attrs);
-                })
-            }
             ItemKind::Enum(_, ref generics) |
             ItemKind::Ty(_, ref generics) |
             ItemKind::Struct(_, ref generics) |
@@ -2415,7 +2388,7 @@ fn resolve_implementation(&mut self,
                                                 visit::walk_impl_item(this, impl_item)
                                             );
                                         }
-                                        ImplItemKind::Method(_, _) => {
+                                        ImplItemKind::Method(..) => {
                                             // If this is a trait impl, ensure the method
                                             // exists in trait
                                             this.check_trait_item(impl_item.ident,
index c2abb79a93abdf06e349ec1b36426edd14647b22..e59efcd68575ff8642b72163386ca5176b44f3a5 100644 (file)
@@ -1293,6 +1293,15 @@ fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a,
         })))
     }
 
+    /// Parse asyncness: `async` or nothing
+    fn parse_asyncness(&mut self) -> IsAsync {
+        if self.eat_keyword(keywords::Async) {
+            IsAsync::Async(ast::DUMMY_NODE_ID)
+        } else {
+            IsAsync::NotAsync
+        }
+    }
+
     /// Parse unsafety: `unsafe` or nothing.
     fn parse_unsafety(&mut self) -> Unsafety {
         if self.eat_keyword(keywords::Unsafe) {
@@ -1342,7 +1351,7 @@ fn parse_trait_item_(&mut self,
             // trait item macro.
             (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
         } else {
-            let (constness, unsafety, 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()?;
@@ -1360,7 +1369,7 @@ fn parse_trait_item_(&mut self,
                     unsafety,
                     constness,
                     abi,
-                    asyncness: IsAsync::NotAsync,
+                    asyncness,
                 },
                 decl: d,
             };
@@ -5425,10 +5434,18 @@ fn is_const_item(&mut self) -> bool {
     /// - `const unsafe fn`
     /// - `extern fn`
     /// - etc
-    fn parse_fn_front_matter(&mut self) -> PResult<'a, (Spanned<Constness>, Unsafety, Abi)> {
+    fn parse_fn_front_matter(&mut self)
+        -> PResult<'a, (
+            Spanned<Constness>,
+            Unsafety,
+            IsAsync,
+            Abi
+        )>
+    {
         let is_const_fn = self.eat_keyword(keywords::Const);
         let const_span = self.prev_span;
         let unsafety = self.parse_unsafety();
+        let asyncness = self.parse_asyncness();
         let (constness, unsafety, abi) = if is_const_fn {
             (respan(const_span, Constness::Const), unsafety, Abi::Rust)
         } else {
@@ -5440,7 +5457,7 @@ fn parse_fn_front_matter(&mut self) -> PResult<'a, (Spanned<Constness>, Unsafety
             (respan(self.prev_span, Constness::NotConst), unsafety, abi)
         };
         self.expect_keyword(keywords::Fn)?;
-        Ok((constness, unsafety, abi))
+        Ok((constness, unsafety, asyncness, abi))
     }
 
     /// Parse an impl item.
@@ -5575,14 +5592,14 @@ fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool)
             Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
                 ast::ImplItemKind::Macro(mac)))
         } else {
-            let (constness, unsafety, 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 decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
             generics.where_clause = self.parse_where_clause()?;
             *at_end = true;
             let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-            let header = ast::FnHeader { abi, unsafety, constness, asyncness: IsAsync::NotAsync };
+            let header = ast::FnHeader { abi, unsafety, constness, asyncness };
             Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(
                 ast::MethodSig { header, decl },
                 body
index bc8b8a152fb2b69797b5f3fc7709483923367f54..817db4bb79ec3a4a586b49cea88bef37731fc259 100644 (file)
@@ -104,10 +104,16 @@ fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
     x
 }
 
-struct Foo {
+struct Foo;
+
+trait Bar {
+    fn foo() {}
+}
+
+impl Foo {
     async fn async_method(x: u8) -> u8 {
         unsafe {
-            await!(unsafe_async_fn())
+            await!(unsafe_async_fn(x))
         }
     }
 }
index 227dd4483f2bf1e1db899fdee30753d5792a1199..085b9499a416bd2ca347365d2bbcaa21cbf78864 100644 (file)
@@ -6,7 +6,7 @@ LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
    |                                               |
    |                                               first lifetime here
    |
-   = help: `async fn` can only accept borrowed values identical lifetimes
+   = help: `async fn` can only accept borrowed values with identical lifetimes
 
 error[E0704]: multiple elided lifetimes used in arguments of `async fn`
   --> $DIR/async-fn-multiple-lifetimes.rs:26:39