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),
)
},
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),
)
},
}
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;
sig,
impl_item_def_id,
impl_trait_return_allow,
+ sig.header.asyncness.is_async(),
),
body_id,
)
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),
}
}
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 {
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(..) =>
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()),
}
}
+ 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 => {
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| {
E0666, // nested `impl Trait` is illegal
E0667, // `impl Trait` in projections
E0696, // `continue` pointing to a labeled block
+ E0706, // `async fn` in trait
}
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.
}
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) => {
}
};
+ // 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();
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) |
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,
})))
}
+ /// 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) {
// 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()?;
unsafety,
constness,
abi,
- asyncness: IsAsync::NotAsync,
+ asyncness,
},
decl: d,
};
/// - `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 {
(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.
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
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))
}
}
}
| |
| 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