Skip to content

Commit 879abb1

Browse files
committed
Add AsyncArgument to AST.
This commit adds an `AsyncArgument` struct to the AST that contains the generated argument and statement that will be used in HIR lowering, name resolution and def collection.
1 parent 41c6bb1 commit 879abb1

File tree

12 files changed

+171
-53
lines changed

12 files changed

+171
-53
lines changed

src/librustc/hir/intravisit.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ impl<'a> FnKind<'a> {
5858
}
5959
}
6060

61-
pub fn header(&self) -> Option<FnHeader> {
61+
pub fn header(&self) -> Option<&FnHeader> {
6262
match *self {
63-
FnKind::ItemFn(_, _, header, _, _) => Some(header),
64-
FnKind::Method(_, sig, _, _) => Some(sig.header),
63+
FnKind::ItemFn(_, _, ref header, _, _) => Some(header),
64+
FnKind::Method(_, ref sig, _, _) => Some(&sig.header),
6565
FnKind::Closure(_) => None,
6666
}
6767
}

src/librustc/hir/lowering.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3000,13 +3000,13 @@ impl<'a> LoweringContext<'a> {
30003000
fn lower_async_body(
30013001
&mut self,
30023002
decl: &FnDecl,
3003-
asyncness: IsAsync,
3003+
asyncness: &IsAsync,
30043004
body: &Block,
30053005
) -> hir::BodyId {
30063006
self.lower_body(Some(decl), |this| {
30073007
if let IsAsync::Async { closure_id, .. } = asyncness {
30083008
let async_expr = this.make_async_expr(
3009-
CaptureBy::Value, closure_id, None,
3009+
CaptureBy::Value, *closure_id, None,
30103010
|this| {
30113011
let body = this.lower_block(body, false);
30123012
this.expr_block(body, ThinVec::new())
@@ -3067,14 +3067,14 @@ impl<'a> LoweringContext<'a> {
30673067
value
30683068
)
30693069
}
3070-
ItemKind::Fn(ref decl, header, ref generics, ref body) => {
3070+
ItemKind::Fn(ref decl, ref header, ref generics, ref body) => {
30713071
let fn_def_id = self.resolver.definitions().local_def_id(id);
30723072
self.with_new_scopes(|this| {
30733073
// Note: we don't need to change the return type from `T` to
30743074
// `impl Future<Output = T>` here because lower_body
30753075
// only cares about the input argument patterns in the function
30763076
// declaration (decl), not the return types.
3077-
let body_id = this.lower_async_body(decl, header.asyncness.node, body);
3077+
let body_id = this.lower_async_body(decl, &header.asyncness.node, body);
30783078

30793079
let (generics, fn_decl) = this.add_in_band_defs(
30803080
generics,
@@ -3565,7 +3565,7 @@ impl<'a> LoweringContext<'a> {
35653565
)
35663566
}
35673567
ImplItemKind::Method(ref sig, ref body) => {
3568-
let body_id = self.lower_async_body(&sig.decl, sig.header.asyncness.node, body);
3568+
let body_id = self.lower_async_body(&sig.decl, &sig.header.asyncness.node, body);
35693569
let impl_trait_return_allow = !self.is_in_trait_impl;
35703570
let (generics, sig) = self.lower_method_sig(
35713571
&i.generics,
@@ -3767,7 +3767,7 @@ impl<'a> LoweringContext<'a> {
37673767
impl_trait_return_allow: bool,
37683768
is_async: Option<NodeId>,
37693769
) -> (hir::Generics, hir::MethodSig) {
3770-
let header = self.lower_fn_header(sig.header);
3770+
let header = self.lower_fn_header(&sig.header);
37713771
let (generics, decl) = self.add_in_band_defs(
37723772
generics,
37733773
fn_def_id,
@@ -3789,10 +3789,10 @@ impl<'a> LoweringContext<'a> {
37893789
}
37903790
}
37913791

3792-
fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
3792+
fn lower_fn_header(&mut self, h: &FnHeader) -> hir::FnHeader {
37933793
hir::FnHeader {
37943794
unsafety: self.lower_unsafety(h.unsafety),
3795-
asyncness: self.lower_asyncness(h.asyncness.node),
3795+
asyncness: self.lower_asyncness(&h.asyncness.node),
37963796
constness: self.lower_constness(h.constness),
37973797
abi: h.abi,
37983798
}
@@ -3812,7 +3812,7 @@ impl<'a> LoweringContext<'a> {
38123812
}
38133813
}
38143814

3815-
fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
3815+
fn lower_asyncness(&mut self, a: &IsAsync) -> hir::IsAsync {
38163816
match a {
38173817
IsAsync::Async { .. } => hir::IsAsync::Async,
38183818
IsAsync::NotAsync => hir::IsAsync::NotAsync,
@@ -4125,7 +4125,7 @@ impl<'a> LoweringContext<'a> {
41254125
})
41264126
}
41274127
ExprKind::Closure(
4128-
capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span
4128+
capture_clause, ref asyncness, movability, ref decl, ref body, fn_decl_span
41294129
) => {
41304130
if let IsAsync::Async { closure_id, .. } = asyncness {
41314131
let outer_decl = FnDecl {
@@ -4163,7 +4163,7 @@ impl<'a> LoweringContext<'a> {
41634163
Some(&**ty)
41644164
} else { None };
41654165
let async_body = this.make_async_expr(
4166-
capture_clause, closure_id, async_ret_ty,
4166+
capture_clause, *closure_id, async_ret_ty,
41674167
|this| {
41684168
this.with_new_scopes(|this| this.lower_expr(body))
41694169
});

src/librustc/hir/map/def_collector.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl<'a> DefCollector<'a> {
6868
id: NodeId,
6969
name: Name,
7070
span: Span,
71-
header: &FnHeader,
71+
header: &'a FnHeader,
7272
generics: &'a Generics,
7373
decl: &'a FnDecl,
7474
body: &'a Block,
@@ -77,6 +77,7 @@ impl<'a> DefCollector<'a> {
7777
IsAsync::Async {
7878
closure_id,
7979
return_impl_trait_id,
80+
..
8081
} => (closure_id, return_impl_trait_id),
8182
_ => unreachable!(),
8283
};
@@ -290,7 +291,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
290291

291292
match expr.node {
292293
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
293-
ExprKind::Closure(_, asyncness, ..) => {
294+
ExprKind::Closure(_, ref asyncness, ..) => {
294295
let closure_def = self.create_def(expr.id,
295296
DefPathData::ClosureExpr,
296297
REGULAR_SPACE,
@@ -300,7 +301,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
300301
// Async closures desugar to closures inside of closures, so
301302
// we must create two defs.
302303
if let IsAsync::Async { closure_id, .. } = asyncness {
303-
let async_def = self.create_def(closure_id,
304+
let async_def = self.create_def(*closure_id,
304305
DefPathData::ClosureExpr,
305306
REGULAR_SPACE,
306307
expr.span);

src/librustc/lint/context.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,22 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
13281328

13291329
run_early_pass!(self, check_mac, mac);
13301330
}
1331+
1332+
fn visit_fn_header(&mut self, header: &'a ast::FnHeader) {
1333+
// Unlike in HIR lowering and name resolution, the `AsyncArgument` statements are not added
1334+
// to the function body and the arguments do not replace those in the declaration. They are
1335+
// still visited manually here so that buffered lints can be emitted.
1336+
if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node {
1337+
for a in arguments {
1338+
// Visit the argument..
1339+
self.visit_pat(&a.arg.pat);
1340+
self.visit_ty(&a.arg.ty);
1341+
1342+
// ..and the statement.
1343+
self.visit_stmt(&a.stmt);
1344+
}
1345+
}
1346+
}
13311347
}
13321348

13331349
struct LateLintPassObjects<'a> {

src/librustc_passes/ast_validation.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ impl<'a> AstValidator<'a> {
222222
}
223223
}
224224

225-
fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
225+
fn check_trait_fn_not_async(&self, span: Span, asyncness: &IsAsync) {
226226
if asyncness.is_async() {
227227
struct_span_err!(self.session, span, E0706,
228228
"trait fns cannot be declared `async`").emit()
@@ -570,7 +570,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
570570
self.invalid_visibility(&impl_item.vis, None);
571571
if let ImplItemKind::Method(ref sig, _) = impl_item.node {
572572
self.check_trait_fn_not_const(sig.header.constness);
573-
self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
573+
self.check_trait_fn_not_async(impl_item.span, &sig.header.asyncness.node);
574574
}
575575
}
576576
}
@@ -642,7 +642,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
642642
self.no_questions_in_bounds(bounds, "supertraits", true);
643643
for trait_item in trait_items {
644644
if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
645-
self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node);
645+
self.check_trait_fn_not_async(trait_item.span, &sig.header.asyncness.node);
646646
self.check_trait_fn_not_const(sig.header.constness);
647647
if block.is_none() {
648648
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {

src/librustc_resolve/lib.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -817,13 +817,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
817817
debug!("(resolving function) entering function");
818818
let (rib_kind, asyncness) = match function_kind {
819819
FnKind::ItemFn(_, ref header, ..) =>
820-
(FnItemRibKind, header.asyncness.node),
820+
(FnItemRibKind, &header.asyncness.node),
821821
FnKind::Method(_, ref sig, _, _) =>
822-
(TraitOrImplItemRibKind, sig.header.asyncness.node),
822+
(TraitOrImplItemRibKind, &sig.header.asyncness.node),
823823
FnKind::Closure(_) =>
824824
// Async closures aren't resolved through `visit_fn`-- they're
825825
// processed separately
826-
(ClosureRibKind(node_id), IsAsync::NotAsync),
826+
(ClosureRibKind(node_id), &IsAsync::NotAsync),
827827
};
828828

829829
// Create a value rib for the function.
@@ -836,16 +836,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
836836
let mut bindings_list = FxHashMap::default();
837837
for argument in &declaration.inputs {
838838
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
839-
840839
self.visit_ty(&argument.ty);
841-
842840
debug!("(resolving function) recorded argument");
843841
}
844842
visit::walk_fn_ret_ty(self, &declaration.output);
845843

846844
// Resolve the function body, potentially inside the body of an async closure
847845
if let IsAsync::Async { closure_id, .. } = asyncness {
848-
let rib_kind = ClosureRibKind(closure_id);
846+
let rib_kind = ClosureRibKind(*closure_id);
849847
self.ribs[ValueNS].push(Rib::new(rib_kind));
850848
self.label_ribs.push(Rib::new(rib_kind));
851849
}

src/librustc_save_analysis/sig.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ impl Sig for ast::Item {
374374

375375
Ok(extend_sig(ty, text, defs, vec![]))
376376
}
377-
ast::ItemKind::Fn(ref decl, header, ref generics, _) => {
377+
ast::ItemKind::Fn(ref decl, ref header, ref generics, _) => {
378378
let mut text = String::new();
379379
if header.constness.node == ast::Constness::Const {
380380
text.push_str("const ");

src/libsyntax/ast.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,31 +1849,48 @@ pub enum Unsafety {
18491849
Normal,
18501850
}
18511851

1852-
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
1852+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1853+
pub struct AsyncArgument {
1854+
/// `__arg0`
1855+
pub ident: Ident,
1856+
/// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`.
1857+
pub arg: Arg,
1858+
/// `let <pat>: <ty> = __arg0;` statement to be inserted at the start of the block.
1859+
pub stmt: Stmt,
1860+
}
1861+
1862+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
18531863
pub enum IsAsync {
18541864
Async {
18551865
closure_id: NodeId,
18561866
return_impl_trait_id: NodeId,
1867+
/// This field stores the arguments and statements that are used in HIR lowering to
1868+
/// ensure that `async fn` arguments are dropped at the correct time.
1869+
///
1870+
/// The argument and statements here are generated at parse time as they are required in
1871+
/// both the hir lowering, def collection and name resolution and this stops them needing
1872+
/// to be created in each place.
1873+
arguments: Vec<AsyncArgument>,
18571874
},
18581875
NotAsync,
18591876
}
18601877

18611878
impl IsAsync {
1862-
pub fn is_async(self) -> bool {
1863-
if let IsAsync::Async { .. } = self {
1879+
pub fn is_async(&self) -> bool {
1880+
if let IsAsync::Async { .. } = *self {
18641881
true
18651882
} else {
18661883
false
18671884
}
18681885
}
18691886

18701887
/// In ths case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
1871-
pub fn opt_return_id(self) -> Option<NodeId> {
1888+
pub fn opt_return_id(&self) -> Option<NodeId> {
18721889
match self {
18731890
IsAsync::Async {
18741891
return_impl_trait_id,
18751892
..
1876-
} => Some(return_impl_trait_id),
1893+
} => Some(*return_impl_trait_id),
18771894
IsAsync::NotAsync => None,
18781895
}
18791896
}
@@ -2213,7 +2230,7 @@ impl Item {
22132230
///
22142231
/// All the information between the visibility and the name of the function is
22152232
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
2216-
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
2233+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
22172234
pub struct FnHeader {
22182235
pub unsafety: Unsafety,
22192236
pub asyncness: Spanned<IsAsync>,

src/libsyntax/ext/placeholders.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
102102
fn remove(&mut self, id: ast::NodeId) -> AstFragment {
103103
self.expanded_fragments.remove(&id).unwrap()
104104
}
105+
106+
fn next_id(&mut self, id: &mut ast::NodeId) {
107+
if self.monotonic {
108+
assert_eq!(*id, ast::DUMMY_NODE_ID);
109+
*id = self.cx.resolver.next_node_id()
110+
}
111+
}
105112
}
106113

107114
impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
@@ -183,9 +190,16 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
183190
noop_visit_block(block, self);
184191

185192
for stmt in block.stmts.iter_mut() {
186-
if self.monotonic {
187-
assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
188-
stmt.id = self.cx.resolver.next_node_id();
193+
self.next_id(&mut stmt.id);
194+
}
195+
}
196+
197+
fn visit_asyncness(&mut self, a: &mut ast::IsAsync) {
198+
noop_visit_asyncness(a, self);
199+
200+
if let ast::IsAsync::Async { ref mut arguments, .. } = a {
201+
for argument in arguments.iter_mut() {
202+
self.next_id(&mut argument.stmt.id);
189203
}
190204
}
191205
}

src/libsyntax/mut_visit.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,9 +679,17 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:
679679

680680
pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T) {
681681
match asyncness {
682-
IsAsync::Async { closure_id, return_impl_trait_id } => {
682+
IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => {
683683
vis.visit_id(closure_id);
684684
vis.visit_id(return_impl_trait_id);
685+
for AsyncArgument { ident, arg, stmt } in arguments.iter_mut() {
686+
vis.visit_ident(ident);
687+
vis.visit_arg(arg);
688+
visit_clobber(stmt, |stmt| {
689+
vis.flat_map_stmt(stmt)
690+
.expect_one("expected visitor to produce exactly one item")
691+
});
692+
}
685693
}
686694
IsAsync::NotAsync => {}
687695
}

0 commit comments

Comments
 (0)