Skip to content

Commit d64e577

Browse files
committed
Async methods
1 parent d02631d commit d64e577

File tree

8 files changed

+122
-79
lines changed

8 files changed

+122
-79
lines changed

src/librustc/hir/lowering.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -2932,7 +2932,7 @@ impl<'a> LoweringContext<'a> {
29322932
AnonymousLifetimeMode::PassThrough,
29332933
|this| {
29342934
hir::TraitItemKind::Method(
2935-
this.lower_method_sig(sig, trait_item_def_id, false),
2935+
this.lower_method_sig(sig, trait_item_def_id, false, false),
29362936
hir::TraitMethod::Required(names),
29372937
)
29382938
},
@@ -2950,7 +2950,7 @@ impl<'a> LoweringContext<'a> {
29502950
AnonymousLifetimeMode::PassThrough,
29512951
|this| {
29522952
hir::TraitItemKind::Method(
2953-
this.lower_method_sig(sig, trait_item_def_id, false),
2953+
this.lower_method_sig(sig, trait_item_def_id, false, false),
29542954
hir::TraitMethod::Provided(body_id),
29552955
)
29562956
},
@@ -3021,8 +3021,18 @@ impl<'a> LoweringContext<'a> {
30213021
}
30223022
ImplItemKind::Method(ref sig, ref body) => {
30233023
let body_id = self.lower_body(Some(&sig.decl), |this| {
3024-
let body = this.lower_block(body, false);
3025-
this.expr_block(body, ThinVec::new())
3024+
if let IsAsync::Async(async_node_id) = sig.header.asyncness {
3025+
let async_expr = this.make_async_expr(
3026+
CaptureBy::Value, async_node_id, None,
3027+
|this| {
3028+
let body = this.lower_block(body, false);
3029+
this.expr_block(body, ThinVec::new())
3030+
});
3031+
this.expr(body.span, async_expr, ThinVec::new())
3032+
} else {
3033+
let body = this.lower_block(body, false);
3034+
this.expr_block(body, ThinVec::new())
3035+
}
30263036
});
30273037
let impl_trait_return_allow = !self.is_in_trait_impl;
30283038

@@ -3036,6 +3046,7 @@ impl<'a> LoweringContext<'a> {
30363046
sig,
30373047
impl_item_def_id,
30383048
impl_trait_return_allow,
3049+
sig.header.asyncness.is_async(),
30393050
),
30403051
body_id,
30413052
)
@@ -3201,10 +3212,11 @@ impl<'a> LoweringContext<'a> {
32013212
sig: &MethodSig,
32023213
fn_def_id: DefId,
32033214
impl_trait_return_allow: bool,
3215+
is_async: bool,
32043216
) -> hir::MethodSig {
32053217
hir::MethodSig {
32063218
header: self.lower_fn_header(sig.header),
3207-
decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, false),
3219+
decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, is_async),
32083220
}
32093221
}
32103222

src/librustc/hir/map/def_collector.rs

+39-13
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,27 @@ impl<'a> DefCollector<'a> {
7373
self.parent_def = parent;
7474
}
7575

76+
fn visit_async_fn(
77+
&mut self,
78+
id: NodeId,
79+
async_node_id: NodeId,
80+
name: Name,
81+
span: Span,
82+
visit_fn: impl FnOnce(&mut DefCollector<'a>)
83+
) {
84+
// For async functions, we need to create their inner defs inside of a
85+
// closure to match their desugared representation.
86+
let fn_def_data = DefPathData::ValueNs(name.as_interned_str());
87+
let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span);
88+
return self.with_parent(fn_def, |this| {
89+
let closure_def = this.create_def(async_node_id,
90+
DefPathData::ClosureExpr,
91+
REGULAR_SPACE,
92+
span);
93+
this.with_parent(closure_def, visit_fn)
94+
})
95+
}
96+
7697
fn visit_macro_invoc(&mut self, id: NodeId) {
7798
if let Some(ref mut visit) = self.visit_macro_invoc {
7899
visit(MacroInvocationData {
@@ -100,19 +121,13 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
100121
return visit::walk_item(self, i);
101122
}
102123
ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..) => {
103-
// For async functions, we need to create their inner defs inside of a
104-
// closure to match their desugared representation.
105-
let fn_def_data = DefPathData::ValueNs(i.ident.name.as_interned_str());
106-
let fn_def = self.create_def(i.id, fn_def_data, ITEM_LIKE_SPACE, i.span);
107-
return self.with_parent(fn_def, |this| {
108-
let closure_def = this.create_def(async_node_id,
109-
DefPathData::ClosureExpr,
110-
REGULAR_SPACE,
111-
i.span);
112-
this.with_parent(closure_def, |this| {
113-
visit::walk_item(this, i);
114-
})
115-
});
124+
return self.visit_async_fn(
125+
i.id,
126+
async_node_id,
127+
i.ident.name,
128+
i.span,
129+
|this| visit::walk_item(this, i)
130+
)
116131
}
117132
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_interned_str()),
118133
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
@@ -212,6 +227,17 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
212227

213228
fn visit_impl_item(&mut self, ii: &'a ImplItem) {
214229
let def_data = match ii.node {
230+
ImplItemKind::Method(MethodSig {
231+
header: FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..
232+
}, ..) => {
233+
return self.visit_async_fn(
234+
ii.id,
235+
async_node_id,
236+
ii.ident.name,
237+
ii.span,
238+
|this| visit::walk_impl_item(this, ii)
239+
)
240+
}
215241
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
216242
DefPathData::ValueNs(ii.ident.name.as_interned_str()),
217243
ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_interned_str()),

src/librustc_passes/ast_validation.rs

+8
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ impl<'a> AstValidator<'a> {
8787
}
8888
}
8989

90+
fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
91+
if asyncness.is_async() {
92+
struct_span_err!(self.session, span, E0706,
93+
"trait fns cannot be declared `async`").emit()
94+
}
95+
}
96+
9097
fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
9198
match constness.node {
9299
Constness::Const => {
@@ -309,6 +316,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
309316
self.no_questions_in_bounds(bounds, "supertraits", true);
310317
for trait_item in trait_items {
311318
if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
319+
self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness);
312320
self.check_trait_fn_not_const(sig.header.constness);
313321
if block.is_none() {
314322
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {

src/librustc_passes/diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -310,4 +310,5 @@ register_diagnostics! {
310310
E0666, // nested `impl Trait` is illegal
311311
E0667, // `impl Trait` in projections
312312
E0696, // `continue` pointing to a labeled block
313+
E0706, // `async fn` in trait
313314
}

src/librustc_resolve/lib.rs

+25-52
Original file line numberDiff line numberDiff line change
@@ -746,15 +746,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
746746
function_kind: FnKind<'tcx>,
747747
declaration: &'tcx FnDecl,
748748
_: Span,
749-
node_id: NodeId) {
750-
let rib_kind = match function_kind {
751-
FnKind::ItemFn(..) => {
752-
ItemRibKind
753-
}
754-
FnKind::Method(_, _, _, _) => {
755-
TraitOrImplItemRibKind
756-
}
757-
FnKind::Closure(_) => ClosureRibKind(node_id),
749+
node_id: NodeId)
750+
{
751+
let (rib_kind, asyncness) = match function_kind {
752+
FnKind::ItemFn(_, ref header, ..) =>
753+
(ItemRibKind, header.asyncness),
754+
FnKind::Method(_, ref sig, _, _) =>
755+
(TraitOrImplItemRibKind, sig.header.asyncness),
756+
FnKind::Closure(_) =>
757+
// Async closures aren't resolved through `visit_fn`-- they're
758+
// processed separately
759+
(ClosureRibKind(node_id), IsAsync::NotAsync),
758760
};
759761

760762
// Create a value rib for the function.
@@ -774,7 +776,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
774776
}
775777
visit::walk_fn_ret_ty(self, &declaration.output);
776778

777-
// Resolve the function body.
779+
// Resolve the function body, potentially inside the body of an async closure
780+
if let IsAsync::Async(async_closure_id) = asyncness {
781+
let rib_kind = ClosureRibKind(async_closure_id);
782+
self.ribs[ValueNS].push(Rib::new(rib_kind));
783+
self.label_ribs.push(Rib::new(rib_kind));
784+
}
785+
778786
match function_kind {
779787
FnKind::ItemFn(.., body) |
780788
FnKind::Method(.., body) => {
@@ -785,6 +793,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
785793
}
786794
};
787795

796+
// Leave the body of the async closure
797+
if asyncness.is_async() {
798+
self.label_ribs.pop();
799+
self.ribs[ValueNS].pop();
800+
}
801+
788802
debug!("(resolving function) leaving function");
789803

790804
self.label_ribs.pop();
@@ -2054,47 +2068,6 @@ impl<'a> Resolver<'a> {
20542068
self.check_proc_macro_attrs(&item.attrs);
20552069

20562070
match item.node {
2057-
ItemKind::Fn(ref declaration,
2058-
FnHeader { asyncness: IsAsync::Async(async_closure_id), .. },
2059-
ref generics,
2060-
ref body) => {
2061-
// Async functions are desugared from `async fn foo() { .. }`
2062-
// to `fn foo() { future_from_generator(move || ... ) }`,
2063-
// so we have to visit the body inside the closure scope
2064-
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
2065-
this.visit_vis(&item.vis);
2066-
this.visit_ident(item.ident);
2067-
this.visit_generics(generics);
2068-
let rib_kind = ItemRibKind;
2069-
this.ribs[ValueNS].push(Rib::new(rib_kind));
2070-
this.label_ribs.push(Rib::new(rib_kind));
2071-
let mut bindings_list = FxHashMap();
2072-
for argument in &declaration.inputs {
2073-
this.resolve_pattern(
2074-
&argument.pat, PatternSource::FnParam, &mut bindings_list);
2075-
this.visit_ty(&*argument.ty);
2076-
}
2077-
visit::walk_fn_ret_ty(this, &declaration.output);
2078-
2079-
// Now resolve the inner closure
2080-
{
2081-
let rib_kind = ClosureRibKind(async_closure_id);
2082-
this.ribs[ValueNS].push(Rib::new(rib_kind));
2083-
this.label_ribs.push(Rib::new(rib_kind));
2084-
// No need to resolve either arguments nor return type,
2085-
// as this closure has neither
2086-
2087-
// Resolve the body
2088-
this.visit_block(body);
2089-
this.label_ribs.pop();
2090-
this.ribs[ValueNS].pop();
2091-
}
2092-
this.label_ribs.pop();
2093-
this.ribs[ValueNS].pop();
2094-
2095-
walk_list!(this, visit_attribute, &item.attrs);
2096-
})
2097-
}
20982071
ItemKind::Enum(_, ref generics) |
20992072
ItemKind::Ty(_, ref generics) |
21002073
ItemKind::Struct(_, ref generics) |
@@ -2415,7 +2388,7 @@ impl<'a> Resolver<'a> {
24152388
visit::walk_impl_item(this, impl_item)
24162389
);
24172390
}
2418-
ImplItemKind::Method(_, _) => {
2391+
ImplItemKind::Method(..) => {
24192392
// If this is a trait impl, ensure the method
24202393
// exists in trait
24212394
this.check_trait_item(impl_item.ident,

src/libsyntax/parse/parser.rs

+23-6
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,15 @@ impl<'a> Parser<'a> {
12931293
})))
12941294
}
12951295

1296+
/// Parse asyncness: `async` or nothing
1297+
fn parse_asyncness(&mut self) -> IsAsync {
1298+
if self.eat_keyword(keywords::Async) {
1299+
IsAsync::Async(ast::DUMMY_NODE_ID)
1300+
} else {
1301+
IsAsync::NotAsync
1302+
}
1303+
}
1304+
12961305
/// Parse unsafety: `unsafe` or nothing.
12971306
fn parse_unsafety(&mut self) -> Unsafety {
12981307
if self.eat_keyword(keywords::Unsafe) {
@@ -1342,7 +1351,7 @@ impl<'a> Parser<'a> {
13421351
// trait item macro.
13431352
(keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
13441353
} else {
1345-
let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
1354+
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
13461355

13471356
let ident = self.parse_ident()?;
13481357
let mut generics = self.parse_generics()?;
@@ -1360,7 +1369,7 @@ impl<'a> Parser<'a> {
13601369
unsafety,
13611370
constness,
13621371
abi,
1363-
asyncness: IsAsync::NotAsync,
1372+
asyncness,
13641373
},
13651374
decl: d,
13661375
};
@@ -5425,10 +5434,18 @@ impl<'a> Parser<'a> {
54255434
/// - `const unsafe fn`
54265435
/// - `extern fn`
54275436
/// - etc
5428-
fn parse_fn_front_matter(&mut self) -> PResult<'a, (Spanned<Constness>, Unsafety, Abi)> {
5437+
fn parse_fn_front_matter(&mut self)
5438+
-> PResult<'a, (
5439+
Spanned<Constness>,
5440+
Unsafety,
5441+
IsAsync,
5442+
Abi
5443+
)>
5444+
{
54295445
let is_const_fn = self.eat_keyword(keywords::Const);
54305446
let const_span = self.prev_span;
54315447
let unsafety = self.parse_unsafety();
5448+
let asyncness = self.parse_asyncness();
54325449
let (constness, unsafety, abi) = if is_const_fn {
54335450
(respan(const_span, Constness::Const), unsafety, Abi::Rust)
54345451
} else {
@@ -5440,7 +5457,7 @@ impl<'a> Parser<'a> {
54405457
(respan(self.prev_span, Constness::NotConst), unsafety, abi)
54415458
};
54425459
self.expect_keyword(keywords::Fn)?;
5443-
Ok((constness, unsafety, abi))
5460+
Ok((constness, unsafety, asyncness, abi))
54445461
}
54455462

54465463
/// Parse an impl item.
@@ -5575,14 +5592,14 @@ impl<'a> Parser<'a> {
55755592
Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
55765593
ast::ImplItemKind::Macro(mac)))
55775594
} else {
5578-
let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
5595+
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
55795596
let ident = self.parse_ident()?;
55805597
let mut generics = self.parse_generics()?;
55815598
let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
55825599
generics.where_clause = self.parse_where_clause()?;
55835600
*at_end = true;
55845601
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
5585-
let header = ast::FnHeader { abi, unsafety, constness, asyncness: IsAsync::NotAsync };
5602+
let header = ast::FnHeader { abi, unsafety, constness, asyncness };
55865603
Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(
55875604
ast::MethodSig { header, decl },
55885605
body

src/test/run-pass/async-await.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,16 @@ unsafe async fn unsafe_async_fn(x: u8) -> u8 {
104104
x
105105
}
106106

107-
struct Foo {
107+
struct Foo;
108+
109+
trait Bar {
110+
fn foo() {}
111+
}
112+
113+
impl Foo {
108114
async fn async_method(x: u8) -> u8 {
109115
unsafe {
110-
await!(unsafe_async_fn())
116+
await!(unsafe_async_fn(x))
111117
}
112118
}
113119
}

src/test/ui/async-fn-multiple-lifetimes.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
66
| |
77
| first lifetime here
88
|
9-
= help: `async fn` can only accept borrowed values identical lifetimes
9+
= help: `async fn` can only accept borrowed values with identical lifetimes
1010

1111
error[E0704]: multiple elided lifetimes used in arguments of `async fn`
1212
--> $DIR/async-fn-multiple-lifetimes.rs:26:39

0 commit comments

Comments
 (0)