mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +00:00
Async methods
This commit is contained in:
parent
d02631d3df
commit
d64e577fa3
@ -2932,7 +2932,7 @@ impl<'a> LoweringContext<'a> {
|
||||
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 @@ impl<'a> LoweringContext<'a> {
|
||||
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 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
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 @@ impl<'a> LoweringContext<'a> {
|
||||
sig,
|
||||
impl_item_def_id,
|
||||
impl_trait_return_allow,
|
||||
sig.header.asyncness.is_async(),
|
||||
),
|
||||
body_id,
|
||||
)
|
||||
@ -3201,10 +3212,11 @@ impl<'a> LoweringContext<'a> {
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,27 @@ impl<'a> DefCollector<'a> {
|
||||
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 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
||||
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 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
||||
|
||||
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()),
|
||||
|
@ -87,6 +87,13 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ 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);
|
||||
self.check_trait_fn_not_const(sig.header.constness);
|
||||
if block.is_none() {
|
||||
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
|
||||
|
@ -310,4 +310,5 @@ register_diagnostics! {
|
||||
E0666, // nested `impl Trait` is illegal
|
||||
E0667, // `impl Trait` in projections
|
||||
E0696, // `continue` pointing to a labeled block
|
||||
E0706, // `async fn` in trait
|
||||
}
|
||||
|
@ -746,15 +746,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||
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 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||
}
|
||||
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 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
// 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 @@ impl<'a> Resolver<'a> {
|
||||
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 @@ impl<'a> Resolver<'a> {
|
||||
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,
|
||||
|
@ -1293,6 +1293,15 @@ impl<'a> Parser<'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 @@ impl<'a> Parser<'a> {
|
||||
// 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 @@ impl<'a> Parser<'a> {
|
||||
unsafety,
|
||||
constness,
|
||||
abi,
|
||||
asyncness: IsAsync::NotAsync,
|
||||
asyncness,
|
||||
},
|
||||
decl: d,
|
||||
};
|
||||
@ -5425,10 +5434,18 @@ impl<'a> Parser<'a> {
|
||||
/// - `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 @@ impl<'a> Parser<'a> {
|
||||
(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 @@ impl<'a> Parser<'a> {
|
||||
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
|
||||
|
@ -104,10 +104,16 @@ unsafe async fn unsafe_async_fn(x: u8) -> 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user